From: "Matthew R Wette jpl nasa gov" <mwette mr-ed JPL NASA GOV>
To: dia-list gnome org
Subject: Re: WMF problems
Date: Fri, 16 Apr 2004 20:11:35 -0700
> * Enrico Weigelt <weigelt@metux.de> [2004-04-16 17:55]:
> >
> > In the current example, talking about "wmf support" is too unclear
> > and misleading for me, since it does not really say, what we do
> > with wmf.
>
> Windows MetaFile ("WMF") and Enhanced windows MetaFile ("EMF") are
> simply a file formats for representing vector graphics. The only thing
> you would ever do with (W/E)MF is use it to contain a vector graphics
> specification in a file. So it's a file i/o issue, and "WMF support"
> can really only have this meaning.
>
> The WMF problem is a frustrating one, because there are a number of
> tools that claim to support it, but they're all either disfunctional
> or non-trivial to install.
A few years ago I started developing some code to convert .fig
files to .wmf. I had been doing everything in python with a
loadable module for low-level .wmf file writing. I also started
work on a dia wmf exporter. These were not finished.
This code is not mature. If someone wants to hack, please proceed.
Three files are included: wmfapi.h wmf1.c wmfmeta.txt
I believe wmfapi.h is from libwmf.
I don't have shar right now so I am including the files in the raw.
wmfmeta.txt explains the wmf format
Matt
===== wmfapi.h =====
#ifndef WMF_HEADER_FILE
#define WMF_HEADER_FILE
#include <stdlib.h>
#include <stdio.h>
#ifndef U32
#define U32 unsigned int
#endif
#ifndef S32
#define S32 int
#endif
#ifndef U16
#define U16 unsigned short
#endif
#ifndef S16
#define S16 short
#endif
#ifndef U8
#define U8 unsigned char
#endif
U32 read_32ubit(FILE *in);
U16 read_16ubit(FILE *in);
#ifndef PI
#ifndef M_PI
#define PI 3.14159265358979323846
#else
#define PI M_PI
#endif
#endif
#ifndef M_2PI
#define M_2PI 6.28318530717958647692
#endif
#define round(a) (int)(((a)<0.0)?(a)-.5:(a)+.5)
#define MM_PER_INCH 25.40
typedef struct tagSIZE
{
U16 cx;
U16 cy;
} SIZE;
typedef struct tagRECT
{
S32 left;
S32 right;
S32 top;
S32 bottom;
}RECT;
typedef struct tagPOINT
{
S32 x;
S32 y;
}POINT;
typedef struct {
S16 size;
S16 numRects;
S16 type; /* NULL, SIMPLE or COMPLEX */
RECT *rects;
RECT extents;
} WINEREGION;
typedef struct tagLOGBRUSH
{
U16 lbStyle;
U16 lbColor[2];
U16 lbHatch;
/* */
void *pointer;
} LOGBRUSH;
typedef struct tagLOGPEN
{
U16 lopnStyle;
U32 lopnWidth;
U16 lopnColor[2];
} LOGPEN;
/* Logical Font */
#define LF_FACESIZE 32
typedef struct tagLOGFONTA
{
U16 lfHeight;
U16 lfWidth;
U16 lfEscapement;
U16 lfOrientation;
U16 lfWeight;
U8 lfItalic;
U8 lfUnderline;
U8 lfStrikeOut;
U8 lfCharSet;
U8 lfOutPrecision;
U8 lfClipPrecision;
U8 lfQuality;
U8 lfPitchAndFamily;
U8 lfFaceName[LF_FACESIZE];
} LOGFONTA;
typedef struct
{
int type;
union
{
LOGBRUSH brush;
LOGPEN pen;
LOGFONTA afont;
int palette;
WINEREGION rgn;
} obj;
} Object;
typedef struct _StandardMetaRecord
{
U32 Size; /* Total size of the record in U16s */
U16 Function; /* Function number (defined in WINDOWS.H) */
S16 *Parameters; /* Parameter values passed to function */
} WMFRECORD;
typedef struct _PlaceableMetaHeader
{
U32 Key; /* Magic number (always 9AC6CDD7h) */
U16 Handle; /* Metafile HANDLE number (always 0) */
S16 Left; /* Left coordinate in metafile units */
S16 Top; /* Top coordinate in metafile units */
S16 Right; /* Right coordinate in metafile units */
S16 Bottom; /* Bottom coordinate in metafile units */
U16 Inch; /* Number of metafile units per inch */
U32 Reserved; /* Reserved (always 0) */
U16 Checksum; /* Checksum value for previous 10 U16s */
} PLACEABLEMETAHEADER;
typedef struct _WindowsMetaHeader
{
U16 FileType; /* Type of metafile (0=memory, 1=disk) */
U16 HeaderSize; /* Size of header in U16S (always 9) */
U16 Version; /* Version of Microsoft Windows used */
U32 FileSize; /* Total size of the metafile in U16s */
U16 NumOfObjects; /* Number of objects in the file */
U32 MaxRecordSize; /* The size of largest record in U16s */
U16 NumOfParams; /* Not Used (always 0) */
} WMFHEAD;
/* PolyFill() Modes */
#define ALTERNATE 1
#define WINDING 2
#define POLYFILL_LAST 2
/* Brush Styles */
#define BS_SOLID 0
#define BS_NULL 1
#define BS_HOLLOW BS_NULL
#define BS_HATCHED 2
#define BS_PATTERN 3
#define BS_INDEXED 4
#define BS_DIBPATTERN 5
#define BS_DIBPATTERNPT 6
#define BS_PATTERN8X8 7
#define BS_DIBPATTERN8X8 8
/* Hatch Styles */
#define HS_HORIZONTAL 0 /* ----- */
#define HS_VERTICAL 1 /* ||||| */
#define HS_FDIAGONAL 2 /* \\\\\ */
#define HS_BDIAGONAL 3 /* ///// */
#define HS_CROSS 4 /* +++++ */
#define HS_DIAGCROSS 5 /* xxxxx */
#define NB_HATCH_STYLES 6
static const char HatchBrushes[NB_HATCH_STYLES + 1][8] =
{
{ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }, /* HS_HORIZONTAL */
{ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, /* HS_VERTICAL */
{ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, /* HS_FDIAGONAL */
{ 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, /* HS_BDIAGONAL */
{ 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08 }, /* HS_CROSS */
{ 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 }, /* HS_DIAGCROSS */
{ 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb } /* Hack for DKGRAY */
};
/* Pen Styles */
#define PS_SOLID 0
#define PS_DASH 1 /* ------- */
#define PS_DOT 2 /* ....... */
#define PS_DASHDOT 3 /* _._._._ */
#define PS_DASHDOTDOT 4 /* _.._.._ */
#define PS_NULL 5
#define PS_INSIDEFRAME 6
#define PS_USERSTYLE 7
#define PS_ALTERNATE 8
#define PS_STYLE_MASK 0x0000000F
#define PS_ENDCAP_ROUND 0x00000000
#define PS_ENDCAP_SQUARE 0x00000100
#define PS_ENDCAP_FLAT 0x00000200
#define PS_ENDCAP_MASK 0x00000F00
#define PS_JOIN_ROUND 0x00000000
#define PS_JOIN_BEVEL 0x00001000
#define PS_JOIN_MITER 0x00002000
#define PS_JOIN_MASK 0x0000F000
#define PS_COSMETIC 0x00000000
#define PS_GEOMETRIC 0x00010000
#define PS_TYPE_MASK 0x000F0000
static const char PEN_dash[] = { 5,3 }; /* ----- ----- ----- */
static const char PEN_dot[] = { 2,2 }; /* -- -- -- -- -- -- */
static const char PEN_dashdot[] = { 4,3,2,3 }; /* ---- -- ---- -- */
static const char PEN_dashdotdot[] = { 4,2,2,2,2,2 }; /* ---- -- -- ---- */
static const char PEN_alternate[] = { 1,1 }; /* FIXME */
/* Object Definitions for EnumObjects() */
#define OBJ_PEN 1
#define OBJ_BRUSH 2
#define OBJ_DC 3
#define OBJ_METADC 4
#define OBJ_PAL 5
#define OBJ_FONT 6
#define OBJ_BITMAP 7
#define OBJ_REGION 8
#define OBJ_METAFILE 9
#define OBJ_MEMDC 10
#define OBJ_EXTPEN 11
#define OBJ_ENHMETADC 12
#define OBJ_ENHMETAFILE 13
/* Modes for SetMapMode */
#define MM_TEXT 1
#define MM_LOMETRIC 2
#define MM_HIMETRIC 3
#define MM_LOENGLISH 4
#define MM_HIENGLISH 5
#define MM_TWIPS 6
#define MM_ISOTROPIC 7
#define MM_ANISOTROPIC 8
/* Text Alignment Options */
#define TA_NOUPDATECP 0
#define TA_UPDATECP 1
#define TA_LEFT 0
#define TA_RIGHT 2
#define TA_CENTER 6
#define TA_TOP 0
#define TA_BOTTOM 8
#define TA_BASELINE 24
#if (WINVER >= 0x0400)
#define TA_RTLREADING 256
#define TA_MASK (TA_BASELINE+TA_CENTER+TA_UPDATECP+TA_RTLREADING)
#else
#define TA_MASK (TA_BASELINE+TA_CENTER+TA_UPDATECP)
#endif
/* Binary raster ops */
#define R2_BLACK 1 /* 0 */
#define R2_NOTMERGEPEN 2 /* DPon */
#define R2_MASKNOTPEN 3 /* DPna */
#define R2_NOTCOPYPEN 4 /* PN */
#define R2_MASKPENNOT 5 /* PDna */
#define R2_NOT 6 /* Dn */
#define R2_XORPEN 7 /* DPx */
#define R2_NOTMASKPEN 8 /* DPan */
#define R2_MASKPEN 9 /* DPa */
#define R2_NOTXORPEN 10 /* DPxn */
#define R2_NOP 11 /* D */
#define R2_MERGENOTPEN 12 /* DPno */
#define R2_COPYPEN 13 /* P */
#define R2_MERGEPENNOT 14 /* PDno */
#define R2_MERGEPEN 15 /* DPo */
#define R2_WHITE 16 /* 1 */
#define R2_LAST 16
/* Ternary raster operations */
#define SRCCOPY (U32)0x00CC0020 /* dest = source */
#define SRCPAINT (U32)0x00EE0086 /* dest = source OR dest */
#define SRCAND (U32)0x008800C6 /* dest = source AND dest */
#define SRCINVERT (U32)0x00660046 /* dest = source XOR dest */
#define SRCERASE (U32)0x00440328 /* dest = source AND (NOT dest) */
#define NOTSRCCOPY (U32)0x00330008 /* dest = (NOT source) */
#define NOTSRCERASE (U32)0x001100A6 /* dest = (NOT src) AND (NOT dest)*/
#define MERGECOPY (U32)0x00C000CA /* dest = (source AND pattern) */
#define MERGEPAINT (U32)0x00BB0226 /* dest = (NOT source) OR dest */
#define PATCOPY (U32)0x00F00021 /* dest = pattern */
#define PATPAINT (U32)0x00FB0A09 /* dest = DPSnoo */
#define PATINVERT (U32)0x005A0049 /* dest = pattern XOR dest */
#define DSTINVERT (U32)0x00550009 /* dest = (NOT dest) */
#define BLACKNESS (U32)0x00000042 /* dest = BLACK */
#define WHITENESS (U32)0x00FF0062 /* dest = WHITE */
/* StretchBlt() Modes */
#define BLACKONWHITE 1
#define WHITEONBLACK 2
#define COLORONCOLOR 3
#define HALFTONE 4
#define MAXSTRETCHBLTMODE 4
#if(WINVER >= 0x0400)
/* New StretchBlt() Modes */
#define STRETCH_ANDSCANS BLACKONWHITE
#define STRETCH_ORSCANS WHITEONBLACK
#define STRETCH_DELETESCANS COLORONCOLOR
#define STRETCH_HALFTONE HALFTONE
#endif /* WINVER >= 0x0400 */
struct _C_DC
{
void *userdata;
LOGBRUSH *brush;
LOGPEN *pen;
LOGFONTA *font;
int key;
struct _C_DC *next;
U16 textcolor[2];
U16 bgcolor[2];
U16 textalign;
U16 bgmode;
U16 polyfillmode;
U16 charextra;
U16 breakextra;
U32 ROPmode;
WINEREGION *hClipRgn;
WINEREGION *hVisRgn;
};
typedef struct _C_DC DC;
struct _C_MetaHeader
{
WMFHEAD *wmfheader;
PLACEABLEMETAHEADER *pmh;
FILE *filein;
long pos;
int placeable;
};
typedef struct _C_MetaHeader * HMETAFILE;
typedef struct _C_Struct
{
/*
Display *display;
Drawable drawable;
*/
void *userdata;
DC *dc;
int preparse;
float xpixeling;
float ypixeling;
float realheight;
float realwidth;
int currentx;
int currenty;
int newleft;
int newtop;
int xViewportOrg;
int yViewportOrg;
int xViewportExt;
int yViewportExt;
int xWindowExt;
int yWindowExt;
int mapmode;
} CSTRUCT;
/*
in the parameter array, y's precede x's
*/
#define META_SAVEDC 0x001E /*i dont think ive saved everything ?*/
#define META_REALIZEPALETTE 0x0035 /*safely ignored methinks*/
#define META_SETPALENTRIES 0x0037 /*safely ignored methinks*/
#define META_CREATEPALETTE 0x00f7 /*not implemented yet*/
#define META_SETBKMODE 0x0102 /*working on it*/
#define META_SETMAPMODE 0x0103 /* more or less implemented*/
#define META_SETROP2 0x0104 /* maybe it works maybe it doesnt*/
#define META_SETPOLYFILLMODE 0x0106
#define META_SETSTRETCHBLTMODE 0x0107 /* dont know yet*/
#define META_SETTEXTCHAREXTRA 0x0108 /* extra space after each character*/
#define META_RESTOREDC 0x0127 /* ive restored everything ?*/
#define META_INVERTREGION 0x012A /* invert the select region*/
#define META_PAINTREGION 0x012B /* paint the selected region*/
#define META_SELECTCLIPREGION 0x012C /* set region to be clip region*/
#define META_SELECTOBJECT 0x012D /* select what object to draw with*/
#define META_SETTEXTALIGN 0x012E /* working on it, vertial done for X*/
#define META_DIBCREATEPATTERNBRUSH 0x0142 /*implemented fully i think*/
#define META_DELETEOBJECT 0x01f0 /* delete an object */
/* deleting selected object makes you fall back to the prev selected object ?*/
#define META_SETBKCOLOR 0x0201
#define META_SETTEXTCOLOR 0x0209 /*text color, stored*/
#define META_SETTEXTJUSTIFICATION 0x020A /* amt of xtra space after each space
#define META_SETWINDOWORG 0x020B /* def origin of the wmf coord sys */
#define META_SETWINDOWEXT 0x020C /* def wid & hei of the coord-system */
#define META_SETVIEWPORTORG 0x020D
#define META_SETVIEWPORTEXT 0x020E /* for MM_ISOTROPIC & MM_ANISOTROPIC */
#define META_OFFSETWINDOWORG 0x020F /* changes org of the logical window */
#define META_OFFSETVIEWPORTORG 0x0211 /* changes org of the device window */
#define META_LINETO 0x0213 /* fairly obvious, w/ clipping engaged*/
#define META_MOVETO 0x0214 /* obvious see code for more*/
#define META_OFFSETCLIPRGN 0x0220 /* move the clipping reg*/
#define META_FILLREGION 0x0228 /* fill selected region w/ sel brush*/
#define META_SETMAPPERFLAGS 0x0231 /* font mapping flag, (ignorable?) */
#define META_SELECTPALETTE 0x0234 /* safely ignored methinks*/
#define META_CREATEFONTINDIRECT 0x02FB /* gd mapping needs to be done */
/* X one needs to be made robust*/
#define META_CREATEPENINDIRECT 0x02FA /* uncertain*/
#define META_CREATEBRUSHINDIRECT 0x02FC /* uncertain*/
#define META_POLYGON 0x0324 /* obvious */
#define META_POLYLINE 0x0325 /* obvious */
#define META_SCALEWINDOWEXT 0x0410 /* modify the extent of the window*/
#define META_SCALEVIEWPORTEXT 0x0412 /* modify the extent of the viewport*/
#define META_EXCLUDECLIPRECT 0x0415 /* remove part of a clipping rect*/
#define META_INTERSECTCLIPRECT 0x0416 /* a clipping rect', used for lines*/
#define META_ELLIPSE 0x0418 /* obvious*/
#define META_FLOODFILL 0x0419 /* reasonably obvious*/
#define META_RECTANGLE 0x041B /* obvious*/
#define META_SETPIXEL 0x041F /*obvious*/
#define META_FRAMEREGION 0x0429 /*reasonably obvious*/
#define META_TEXTOUT 0x0521
#define META_POLYPOLYGON 0x0538 /* working*/
#define META_EXTFLOODFILL 0x0548 /* what are filltypes ?*/
#define META_ROUNDRECT 0x061C /* reasonably obvious*/
#define META_PATBLT 0x061D /* more ROP stuff*/
#define META_ESCAPE 0x0626 /* i think i can ignore this one*/
#define META_CREATEREGION 0x06FF /* awkward*/
#define META_ARC 0x0817 /* obvious*/
#define META_PIE 0x081A /* a pie*/
#define META_CHORD 0x0830 /* a chord*/
#define META_DIBBITBLT 0x0940 /* not so sure yet */
#define META_EXTTEXTOUT 0x0a32 /* working on it */
#define META_DIBSTRETCHBLT 0x0b41 /* working on it */
#define META_SETDIBTODEV 0x0d33 /* compl'd mech' 2 cp graphic 2 screen*/
#define META_STRETCHDIB 0x0f43 /* working on it*/
/* Background Modes */
#define TRANSPARENT 1
#define OPAQUE 2
#define BKMODE_LAST 2
#define ETO_OPAQUE 0x0002
#define ETO_CLIPPED 0x0004
#if(WINVER >= 0x0400)
#define ETO_GLYPH_INDEX 0x0010
#define ETO_RTLREADING 0x0080
#endif /* WINVER >= 0x0400 */
/* ExtFloodFill style flags */
#define FLOODFILLBORDER 0
#define FLOODFILLSURFACE 1
/* Regions */
#define ERROR 0
#define NULLREGION 1
#define SIMPLEREGION 2
#define COMPLEXREGION 3
#define RGN_AND 1
#define RGN_OR 2
#define RGN_XOR 3
#define RGN_DIFF 4
#define RGN_COPY 5
int NormY(S16 in,CSTRUCT *cstruct);
int ScaleY(S16 in,CSTRUCT *cstruct);
int NormX(S16 in,CSTRUCT *cstruct);
int ScaleX(S16 in,CSTRUCT *cstruct);
U16 AldusChecksum(PLACEABLEMETAHEADER *pmh);
int FileIsPlaceable(char *file);
HMETAFILE GetMetaFile(char *file);
HMETAFILE GetPlaceableMetaFile(char *file);
WMFHEAD *GetRealMetaFile(FILE *filein);
void wmfinit(CSTRUCT *cstruct);
void parseROP(CSTRUCT *cstruct,U32 dwROP,U16 x, U16 y, U16 width, U16 height);
int PlayMetaFile(void *,HMETAFILE file);
WMFHEAD *GetRealMetaFile(FILE *filein);
void do_pixeling(CSTRUCT *cstruct, HMETAFILE file);
void wmfdebug(FILE *stream,char *fmt, ...);
typedef struct tag_wmf_functions
{
int (*pixel_width)(CSTRUCT *);
int (*pixel_height)(CSTRUCT *);
int (*mm_width)(CSTRUCT *);
int (*mm_height)(CSTRUCT *);
void (*draw_ellipse)(CSTRUCT*,WMFRECORD*);
void (*draw_simple_arc)(CSTRUCT *,WMFRECORD *);
void (*draw_arc)(CSTRUCT*,WMFRECORD*,int finishing);
void (*draw_pie)(CSTRUCT *,WMFRECORD *);
void (*draw_chord)(CSTRUCT *,WMFRECORD *);
void (*draw_polygon)(CSTRUCT*,WMFRECORD*);
void (*draw_polypolygon)(CSTRUCT*,WMFRECORD*);
void (*draw_rectangle)(CSTRUCT*,WMFRECORD*);
void (*draw_round_rectangle)(CSTRUCT *,WMFRECORD *);
void (*draw_line)(CSTRUCT*,WMFRECORD*);
void (*draw_polylines)(CSTRUCT *,WMFRECORD *);
void (*draw_text)(CSTRUCT *cstruct,char *str,RECT *arect,U16 flags,U16 *lpDx,U16 x,U16 y);
void (*set_pixel)(CSTRUCT *,WMFRECORD *);
void (*flood_fill)(CSTRUCT *,WMFRECORD *);
void (*ext_flood_fill)(CSTRUCT *,WMFRECORD *);
void (*fill_opaque)(CSTRUCT *,WMFRECORD *);
void (*parseROP)(CSTRUCT *,U32 ,U16 , U16, U16 , U16 );
void (*setfillstyle)(CSTRUCT *,LOGBRUSH *,DC *);
void (*setpenstyle)(CSTRUCT *,LOGPEN *,DC *);
void (*set_pmf_size)(CSTRUCT *,HMETAFILE );
void (*clip_rect)(CSTRUCT *);
void (*no_clip_rect)(CSTRUCT *);
void (*copy_xpm)(CSTRUCT *,U16, U16, U16 , U16 ,U16,U16,char *,U32 );
void (*paint_rgn)(CSTRUCT *, WINEREGION *rgn);
void (*frame_rgn)(CSTRUCT *, WINEREGION *rgn,U16,U16);
void (*copyUserData)(CSTRUCT *,DC *,DC *);
void (*restoreUserData)(CSTRUCT *,DC *);
void (*freeUserData)(CSTRUCT *,DC *);
void *(*initial_userdata)(CSTRUCT *);
void (*finish)(CSTRUCT *);
}wmf_functions;
extern wmf_functions *wmffunctions;
typedef void (*voidProcp)();
static void REGION_SubtractRegion(WINEREGION *regD, WINEREGION *regM,
WINEREGION *regS );
static void REGION_SubtractO(WINEREGION *pReg, RECT *r1, RECT *r1End,
RECT *r2, RECT *r2End, U16 top, U16 bottom);
void SetRectRgn(WINEREGION *rgn, S16 left, S16 top, S16 right, S16 bottom );
S16 CombineRgn(WINEREGION *destObj, WINEREGION *src1Obj, WINEREGION *src2Obj,
S16 mode);
#define EMPTY_REGION(pReg) { \
(pReg)->numRects = 0; \
(pReg)->extents.left = (pReg)->extents.top = 0; \
(pReg)->extents.right = (pReg)->extents.bottom = 0; \
(pReg)->type = NULLREGION; \
}
static void REGION_CopyRegion(WINEREGION *dst, WINEREGION *src);
static S16 REGION_Coalesce (
WINEREGION *pReg, /* Region to coalesce */
S16 prevStart, /* Index of start of previous band */
S16 curStart /* Index of start of current band */
);
static void REGION_RegionOp(
WINEREGION *newReg, /* Place to store result */
WINEREGION *reg1, /* First region in operation */
WINEREGION *reg2, /* 2nd region in operation */
void (*overlapFunc)(), /* Function to call for over-lapping bands */
void (*nonOverlap1Func)(), /* Function to call for non-overlapping bands in region 1 */
void (*nonOverlap2Func)() /* Function to call for non-overlapping bands in region 2 */
);
#define MEMCHECK(reg, rect, firstrect){\
if ((reg)->numRects >= ((reg)->size - 1)){\
(firstrect) = realloc(\
(firstrect), (2 * (sizeof(RECT)) * ((reg)->size)));\
if ((firstrect) == 0)\
return;\
(reg)->size *= 2;\
(rect) = &(firstrect)[(reg)->numRects];\
}\
}
#define REGION_NOT_EMPTY(pReg) pReg->numRects
static void REGION_UnionO(WINEREGION *pReg, RECT *r1, RECT *r1End,
RECT *r2, RECT *r2End, S16 top, S16 bottom);
static void REGION_UnionNonO(WINEREGION *pReg, RECT *r, RECT *rEnd, S16 top,
S16 bottom);
static void REGION_UnionNonO(WINEREGION *pReg, RECT *r, RECT *rEnd, S16 top,
S16 bottom);
static void REGION_UnionRegion(WINEREGION *newReg, WINEREGION *reg1,
WINEREGION *reg2);
static void REGION_SubtractNonO1(WINEREGION *pReg, RECT *r, RECT *rEnd,
U16 top, U16 bottom);
static void REGION_SetExtents (WINEREGION *pReg);
static void REGION_IntersectRegion(WINEREGION *newReg, WINEREGION *reg1,
WINEREGION *reg2);
static void REGION_IntersectO(WINEREGION *pReg, RECT *r1, RECT *r1End,
RECT *r2, RECT *r2End, S16 top, S16 bottom);
S16 CLIPPING_IntersectClipRect(CSTRUCT *cstruct, S16 left, S16 top,
S16 right, S16 bottom, U16 flags );
S16 OffsetRgn(WINEREGION *rgn, S16 x, S16 y );
/* 1 if two RECTs overlap.
* 0 if two RECTs do not overlap.
*/
#define EXTENTCHECK(r1, r2) \
((r1)->right > (r2)->left && \
(r1)->left < (r2)->right && \
(r1)->bottom > (r2)->top && \
(r1)->top < (r2)->bottom)
#define CLIP_INTERSECT 0x0001
#define CLIP_EXCLUDE 0x0002
#define CLIP_KEEPRGN 0x0004
#ifdef MAX
#undef MAX
#endif
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#ifdef MIN
#undef MIN
#endif
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
===== wmf1.c =====
/* Dia -- an diagram creation/manipulation program
* Copyright (C) 1998 Alexander Larsson
*
* wmf1.c -- WMF export plugin for dia
* Copyright (C) 2002, Matt Wette <mwette@alumni.caltech.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <math.h>
#include <glib.h>
#include "intl.h"
#include "message.h"
#include "geometry.h"
#include "render.h"
#include "filter.h"
#include "plug-ins.h"
#include "wmfapi.h"
#define DEF_UNION(T) union T ## _u { T v; char c[sizeof(T)]; }
#ifdef LITTLE_ENDIAN
#define DEF_RD(T) \
static int rd_ ## T (char *buf, T *val) { \
union T ## _u u; int i; \
for (i = 0; i < sizeof(T); i++) u.c[i] = buf[i]; \
*val = u.v; \
return sizeof(T); \
}
#define DEF_WR(T) \
static int wr_ ## T (char *buf, T val) { \
union T ## _u u; int i; \
u.v = val; \
for (i = 0; i < sizeof(T); i++) buf[i] = u.c[i]; \
return sizeof(T); \
}
#else /* BIG_ENDIAN */
#define DEF_RD(T) \
static int rd_ ## T (char *buf, T *val) { \
union T ## _u u; int i; \
for (i = 0; i < sizeof(T); i++) u.c[i] = buf[sizeof(T)-i-1]; \
*val = u.v; \
return sizeof(T); \
}
#define DEF_WR(T) \
static int wr_ ## T (char *buf, T val) { \
union T ## _u u; int i; \
u.v = val; \
for (i = 0; i < sizeof(T); i++) buf[sizeof(T)-i-1] = u.c[i]; \
return sizeof(T); \
}
#endif
DEF_UNION(U16);
DEF_RD(U16)
DEF_WR(U16)
DEF_UNION(S16);
DEF_RD(S16)
DEF_WR(S16)
DEF_UNION(U32);
DEF_RD(U32)
DEF_WR(U32)
DEF_UNION(S32);
DEF_RD(S32)
DEF_WR(S32)
static U16
checksum(U16 *v, int n)
{
int i;
U16 sum = 0;
for (i = 0; i < n; i++) {
sum ^= v[i];
}
return sum;
}
static int
rd_size(char *buf, SIZE *val)
{
rd_U16(buf+0, &val->cx);
rd_U16(buf+2, &val->cy);
return 4;
}
static int
wr_size(char *buf, SIZE *val)
{
wr_U16(buf+0, val->cx);
wr_U16(buf+2, val->cy);
return 4;
}
static int
wr_placeable(char *buf, int left, int top, int right, int bottom, int inch)
{
int n = 0;
#if 0
printf("wr_placeable: left=%d top=%d right=%d bottom=%d inch=%d\n",
left, top, right, bottom, inch);
#endif
buf[0] = 0xd7; buf[1] = 0xcd;
buf[2] = 0xc6; buf[3] = 0x9a;
n = 4;
n += wr_U16(buf+n, 0); /* Handle */
n += wr_S16(buf+n, (S16)left); /* Left */
n += wr_S16(buf+n, (S16)top); /* Top */
n += wr_S16(buf+n, (S16)right); /* Right */
n += wr_S16(buf+n, (S16)bottom); /* Bottom */
n += wr_U16(buf+n, (U16)inch); /* Inch */
n += wr_U32(buf+n, 0); /* Reserved */
n += wr_U16(buf+n, checksum((U16*)buf+4, 8));
return n;
}
static int
rd_header(char *buf, int *filesize, int *numobj, int *maxrecsize)
{
int n = 0;
U16 u16;
U32 u32;
n += rd_U16(buf+n, &u16); /* file type */
n += rd_U16(buf+n, &u16); /* header size */
if (u16 != 9) return -1;
n += rd_U16(buf+n, &u16); /* version */
n += rd_U32(buf+n, &u32); *filesize = u32;
n += rd_U16(buf+n, &u16); *numobj = u16;
n += rd_U32(buf+n, &u32); *maxrecsize = u32;
n += rd_U16(buf+n, &u16); /* num params */
return n;
}
static int
wr_header(char *buf, int filesize, int numobj, int maxrecsize)
{
int n = 0;
#if 0
printf("wr_header: filesize=%d numobj=%d maxrecsize=%d\n",
filesize, numobj, maxrecsize);
#endif
n += wr_U16(buf+n, 1); /* FileType */
n += wr_U16(buf+n, 9); /* HeaderSize */
n += wr_U16(buf+n, 768); /* Version */
n += wr_U32(buf+n, (U32)filesize); /* FileSize */
n += wr_U16(buf+n, (U16)numobj); /* NumOfObjects */
n += wr_U32(buf+n, (U32)maxrecsize); /* MaxRecordSize */
n += wr_U16(buf+n, 0); /* NumOfParams */
return n;
}
static int
rd_record(char *buf, int *func, int *narg, S16 *args)
{
int n = 0;
U32 size;
U16 f;
/* won't work */
n += rd_U32(buf+n, &size);
n += rd_U16(buf+n, &f);
*func = (int)f;
*narg = size - 3;
while (size > 3) {
n += rd_U16(buf+n, args++);
size--;
}
return n;
}
static int
wr_record1(char *buf, int func, int narg, U16 *args)
{
int i, n = 0;
int val;
#if 0
printf("wr_record1: func=0x%x narg=%d\n", func, narg);
#endif
n += wr_U32(buf+n, 3+narg); /* size */
n += wr_U16(buf+n, func); /* function */
for (i = 0; i < narg; i++) {
n += wr_S16(buf+n, (S16)args[i]); /* params */
}
return n;
}
static int
wr_record(char *buf, int func, int narg, ...)
{
va_list pa;
int i, n = 0;
int val;
va_start(pa, narg);
n += wr_U32(buf+n, 3+narg); /* size */
n += wr_U16(buf+n, func); /* function */
for (i = 0; i < narg; i++) {
val = va_arg(pa, int);
n += wr_S16(buf+n, (S16)val); /* params */
}
va_end(pa);
return n;
}
/* --- the renderer --- */
#define MY_RENDERER_NAME "WMF1"
typedef struct _MyRenderer MyRenderer;
struct _MyRenderer {
Renderer renderer;
FILE *fp; /* where to dump */
int fs; /* file size */
int ps; /* prolog size???? */
};
#include "../renderer.inc"
static void
begin_render(MyRenderer *renderer, DiagramData *data)
{
}
static void
end_render(MyRenderer *renderer)
{
}
static void
set_linewidth(MyRenderer *renderer, real linewidth)
{
}
static void
set_linecaps(MyRenderer *renderer, LineCaps mode)
{
}
static void
set_linejoin(MyRenderer *renderer, LineJoin mode)
{
}
static void
set_linestyle(MyRenderer *renderer, LineStyle mode)
{
}
static void
set_dashlength(MyRenderer *renderer, real length)
{
}
static void
set_fillstyle(MyRenderer *renderer, FillStyle mode)
{
}
static void
set_font(MyRenderer *renderer, Font *font, real height)
{
}
static void
draw_line(MyRenderer *renderer, Point *start, Point *end, Color *line_colour)
{
MyRenderer *r = renderer;
int rs;
char buf[128];
rs = wr_record(buf, META_MOVETO, 2, 10, 10); /* y first, then x */
fwrite(buf, rs, 1, r->fp);
r->fs += rs; r->rc++;
rs = wr_record(buf, META_LINETO, 2, 20, 20); /* y first, then x */
write(fd, buf, rs);
fs += rs; rc++;
}
static void
draw_polyline(MyRenderer *renderer, Point *points, int num_points,
Color *line_colour)
{
}
static void
draw_polygon(MyRenderer *renderer, Point *points, int num_points,
Color *line_colour)
{
}
static void
fill_polygon(MyRenderer *renderer, Point *points, int num_points,
Color *colour)
{
}
static void
draw_rect(MyRenderer *renderer, Point *ul_corner, Point *lr_corner,
Color *colour)
{
}
static void
fill_rect(MyRenderer *renderer, Point *ul_corner, Point *lr_corner,
Color *colour)
{
}
static void
draw_arc(MyRenderer *renderer, Point *center, real width, real height,
real angle1, real angle2, Color *colour)
{
}
static void
fill_arc(MyRenderer *renderer, Point *center, real width, real height,
real angle1, real angle2, Color *colour)
{
}
static void
draw_ellipse(MyRenderer *renderer, Point *center, real width, real height,
Color *colour)
{
}
static void
fill_ellipse(MyRenderer *renderer, Point *center, real width, real height,
Color *colour)
{
}
static void
draw_bezier(MyRenderer *renderer, BezPoint *points, int numpoints,
Color *colour)
{
}
static void
fill_bezier(MyRenderer *renderer, BezPoint *points, int numpoints,
Color *colour)
/* Last point must be same as first point */
{
}
static void
draw_string(MyRenderer *renderer, const char *text, Point *pos,
Alignment alignment, Color *colour)
{
}
static void
draw_image(MyRenderer *renderer, Point *point, real width, real height,
DiaImage image)
{
}
static void
export_data(DiagramData *data, const gchar *filename,
const gchar *diafilename, void* user_data)
{
MyRenderer *r;
WMFHEAD head;
int left, top, right, bottom, inch;
int rs;
char buf[256];
r = g_new(MyRenderer, 1);
r->renderer.ops = &MyRenderOps;
r->renderer.is_interactive = 0;
r->renderer.interactive_ops = NULL;
r->fp = fopen(filename, "wb");
left = 0;
top = 0;
right = 144;
bottom = 72;
inch = ???;
rs = wr_placeable(buf, left, top, right, bottom, inch);
fwrite(buf, rs, 1, r->fp);
r->fs += rs;
r->ps = rs;
r->head.FileType = 1;
r->head.HeaderSize = 9;
r->head.Version = 768;
r->head.FileSize = 0; /* 7574 bytes -> FileSize=3756 */
r->head.NumOfObjects = 2;
r->head.MaxRecordSize = 5; /* 3 + max-param */
r->head.NumOfParams = 0;
rs = wr_head(buf, &r->head);
fwrite(buf, rs, 1, r->fp);
fs += rs;
rs = wr_record(buf, META_SETWINDOWORG, 2, 0, 0);
fwrite(buf, rs, 1, r->fp);
r->fs += rs; r->rc++;
rs = wr_record(buf, META_SETWINDOWEXT, 2, 144, 144);
fwrite(buf, rs, 1, r->fp);
r->fs += rs; r->rc++;
/* ??? */
data_render(data, (Renderer *)renderer, NULL, NULL, NULL);
/* Rewrite the header. */
fseek(f->fp, ps, SEEK_SET); /* skip PMH */
r->head.FileSize = fs;
r->head.NumOfObjects = rc;
rs = wr_head(buf, &r->head);
fwrite(buf, rs, 1, f->fp);
}
static const gchar *extensions[] = { "wmf", NULL };
static DiaExportFilter my_export_filter = {
N_(MY_RENDERER_NAME),
extensions,
export_data
};
/* ===== dia plug-in interface ============================================ */
DIA_PLUGIN_CHECK_INIT
PluginInitResult
dia_plugin_init(PluginInfo *info)
{
if (!dia_plugin_info_init(info, "HPGL",
_("HP Graphics Language export filter"),
NULL, NULL))
return DIA_PLUGIN_INIT_ERROR;
filter_register_export(&my_export_filter);
return DIA_PLUGIN_INIT_OK;
}
/* --- last line of wmf1.c --- */
===== wmfmeta.txt =====
This summary comes from the Microsoft Developers Network CD:
Enhanced Metafiles in Win32
Abstract
With the advent of the Microsoftr Win32 Application
Programming Interface (API), a new metafile format called
enhanced metafiles has been introduced. The overall design goal
of the enhanced metafile was to describe a picture without any
coding restrictions and to make a metafile easier to use.
Enhanced metafiles have many advantages over the older
Windows metafiles found in Microsoft Windows version 3.1
(Win16). Improvements found in the enhanced metafile include an
expanded header, a description string, a metafile palette, and an
increase in the number and type of graphics device interface
(GDI) functions that may be recorded. In addition to these
enhancements, the metafile record and playback code in Win32
has been designed to remove all of the restrictions that applied to
Windows metafiles with respect to scaling, clipping, embedding,
and querying, among others. To top it off, enhanced metafiles
may be played on any device in a device-independent manner.
This article describes the differences between Windows metafiles
and enhanced metafiles. Sample code that illustrates the basic
concepts of creating and playing enhanced metafiles is provided
at the end of this article.
Introduction
The tried-and-true Microsoftr Windows metafile has been an
invaluable aid to the development of numerous drawing and
presentation applications for Windows. However, the "vanilla"
Windows metafile did not address issues related to scalability
and device independence. Left on their own, developers
attempted to address this issue in various ways. Some
developers embedded application, location, or scaling comments
in the metafiles. This resulted in extremely nonportable metafiles.
Others added headers to the metafile that provided various
application-specific information. The net result of most of these
efforts was, once again, nonportable metafiles. However, one of
these endeavorsplaceable metafilescaught on. Developed by
Aldus Corporation, placeable metafiles include a 22-byte header
that provides, among other things, mapping and measurement
information that can be used to scale the metafile.
The proliferation of the placeable metafile, other homegrown
formats, and the confusion of many developers regarding the use
of metafiles led to a demand for a metafile format that addressed
all of the development community's needs. Thus the Win32
enhanced metafile was born. Developed by Microsoft, the
enhanced metafile distinguishes itself from the Windows metafile
in that it is device-independent and much easier to use. Easier to
use? You bet! Remember having to code two paths to deal with
drawing? One code path drew to the screen; the second code
path drew to metafiles. The only way to get around this was to
use a subset of graphics device interface (GDI) functions that
used logical coordinates. Although this permitted limited scaling
capabilities, it restricted the use of many helpful GDI functions.
You definitely couldn't query the metafile device context (DC) for
information such as window origins and extents. With the advent
of the enhanced metafile, those restrictions are unnecessary! A
single code path is all that is required to draw to any DC,
whether it be a metafile, screen, or printer DC. Furthermore, you
no longer need to use a subset of GDI; for example, you can now
do the following:
DeleteObject(SelectObject(hdcMeta, hbrOldBrush));
Yes, the old object versus TRUE or FALSE is returned by
SelectObject when used with a metafile DC. This was not
possible with Windows metafiles and is a good indication of the
potential for success of the enhanced metafile. Finally, in an
enhanced metafile, you can query the current position in the client area.
But what about all of those Windows metafiles? There are
thousands of them in the marketplace. It would be a shame to
see them go to waste. With this in mind, Win32 functions were
written that convert Windows metafiles to enhanced metafiles.
However, enhanced metafiles cannot be used in Win16. Figure 1
illustrates the compatibility of the two metafile formats and
environments.
ED. NOTE: Figures are not available in this plain text version
of the specification.
Figure 1. Metafile compatibility in the Win16 and Win32 environments
This article discusses the differences between the Windows
metafile and the enhanced metafile, the format of the enhanced
metafile, its features, and techniques for its use.
Windows Metafiles vs. Enhanced Metafiles
A Windows metafile is used for applications written using the
Windows version 3.x application programming interface (API).
The format of a Windows metafile consists of a header and an
array of metafile records. Windows metafiles are limited in their
capabilities and should rarely be used in Win32-based
applications. That being said, the Windows metafile functions are
supported in Win32 to maintain backward compatibility with
applications that use the older Windows metafiles.
An enhanced metafile is used in applications written using the
Win32 API. (Win32s, however, does not implement enhanced
metafiles.) The enhanced format consists of a header, a table of
handles to GDI objects, a private palette, and an array of metafile
records. Enhanced metafiles provide true device independence.
You can think of the picture stored in an enhanced metafile as a
snapshot of the video display taken at a particular moment. This
snapshot maintains its dimensions no matter where it appears:
on a printer, a plotter, the desktop, or in the client area of any
Win32-based application.
Metafile Structure
At first glance, Windows metafiles and enhanced metafiles share
the same overall structure. They are an array of variable-length
structures called metafile records. The first records in the
metafile specify general information such as the resolution of the
device on which the picture was created, the dimensions of the
picture, and so on. The remaining records, which constitute the
bulk of any metafile, correspond to the GDI functions required to
draw the picture.
A closer inspection reveals a number of differences between
them, as shown in Figure 2. Unlike the Windows metafile, the
enhanced metafile has a different header and may include a
description string and an optional palette stored in a special
end-of-file record. The enhanced metafile also provides support
for additional types of records.
ED. NOTE: Figure is not available in this plain text version
of the spec.
Figure 2. Structure of a Windows metafile and an enhanced metafile
Enhanced metafile header
The major difference between the Windows metafile header and
the enhanced metafile header is that the Windows metafile
header contains only size and version information, whereas the
enhanced metafile header contains dimension and resolution
information, as well as size and version information. The
Windows metafile header has the following form:
typedef struct tagMETAHEADER {
WORD mtType;
WORD mtHeaderSize;
WORD mtVersion;
DWORD mtSize;
WORD mtNoObjects;
DWORD mtMaxRecord;
WORD mtNoParameters;
} METAHEADER;
In contrast, notice the added dimension and resolution
information in the code for an enhanced metafile header below.
This information is used by the metafile playback functions to
achieve device independence:
typedef struct tagENHMETAHEADER
{
DWORD iType; // Record type EMR_HEADER.
DWORD nSize; // Record size in bytes. This may be greater
// than the sizeof(ENHMETAHEADER).
RECTL rclBounds; // Inclusive-inclusive bounds in device units.
RECTL rclFrame; // Inclusive-inclusive Picture Frame of
// metafile in .01 mm units.
DWORD dSignature; // Signature. Must be ENHMETA_SIGNATURE.
DWORD nVersion; // Version number.
DWORD nBytes; // Size of the metafile in bytes.
DWORD nRecords; // Number of records in the metafile.
WORD nHandles; // Number of handles in the handle table.
// Handle index zero is reserved.
WORD sReserved; // Reserved. Must be zero.
DWORD nDescription; // Number of chars in the unicode description string.
// This is 0 if there is no description string.
DWORD offDescription; // Offset to the metafile description record.
// This is 0 if there is no description string.
DWORD nPalEntries; // Number of entries in the metafile palette.
SIZEL szlDevice; // Size of the reference device in pixels.
SIZEL szlMillimeters; // Size of the reference device in millimeters.
} ENHMETAHEADER;
A good question at this point might be, "How much of the header
information in the enhanced metafile do I need to provide?" When
you call CreateEnhMetafile, you provide a long pointer to a
rectangle that specifies the picture frame, and you provide a DC
that serves as a reference. The members szlDevice and
szlMillimeters are derived from the reference DC. You can also
provide a long pointer to a string that describes the metafile.
rclFrame
The picture frame is stored in the metafile header structure
member rclFrame. When you create the metafile using
CreateEnhMetaFile, a pointer to a RECT structure (lpRect) is
among the parameters. It is this rectangle that specifies the
picture frame. The left and top members of the RECT structure
must be values less than the right and bottom members,
respectively. Points along the edges of the rectangle are included
in the picture. If lpRect is NULL, GDI computes the dimensions
of the smallest rectangle that surrounds the picture. The lpRect
parameter should be provided whenever possible.
nDescription and offDescription
Information regarding the description string is maintained in two
structure members of the metafile header, nDescription and
offDescription. This string is also specified when you create the
metafile using CreateEnhMetaFile. The lpDescription parameter
contains the address of the description string. When the metafile
is created, the length of the description string is stored in the
metafile header. When the metafile is closed, GDI writes the
string to the metafile and updates offDescription in the
header.
nPalEntries
As palettes are created and selected into a metafile DC, GDI
accumulates the palette entries and places them in a "metafile
palette." This palette is located in the EMR_EOF record. An
application can store the palette in an enhanced metafile by
calling either the CreatePalette or SetPaletteEntries function
and the SelectPalette function before creating the picture.
nPalEntries is updated as the palette is collected in the
metafile palette.
Enhanced metafile records
The Windows metafile record and the enhanced metafile record
are similar in structure and size (see code below). However,
before breathing a sigh of relief, take a closer look at the record
structure. The size and type members are reversed. This could
be a potential pitfall when porting existing 16-bit Windows- based
applications to Win32. Take note that the array of parameters is
now an array of DWORD values to accommodate the 32-bit girth of GDI.
typedef struct tagMETARECORD
{
DWORD rdSize; // Record size in bytes
WORD rdFunction; // Record type META_XXX
WORD rdParm[1]; // WORD array of parameters
} METARECORD;
typedef struct tagENHMETARECORD
{
DWORD iType; // Record type EMR_XXX
DWORD nSize; // Record size in bytes
DWORD dParm[1]; // DWORD Array of parameters
} ENHMETARECORD;
Several new metafile records have been added to an already
extensive list of records. Table 1 lists the records found in
enhanced metafile records with their corresponding iType values,
which can be found in WINGDI.H. Some of the records seem to
be similar, for example, EMR_EXTTEXTOUTA and
EMR_EXTTEXTOUTW. The A specifies that the text is based on
ANSI and the W indicates that it is based on UNICODE. Another
similar pair is EMR_POLYLINE and EMR_POLYLINE16. The 16
indicates that GDI has converted the points for PolyLine to 16
bits for the purpose of saving space in the metafile.
Table 1. Enhanced Metafile Records
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
Of the records listed in Table 1, two are present in every
enhanced metafile. The first record in any enhanced metafile is
the metafile header. The value of this record is EMR_HEADER
(1). The last record of an enhanced metafile is always the
end-of-file record. The value of this record is EMR_EOF (14).
In addition to the enhanced metafile header and metafile records,
two additional pieces of data may be found in an enhanced
metafile. The optional description string follows the enhanced
metafile header. An optional color palette, if it exists, is
contained in a special enhanced metafile record, the EMR_EOF
record. The EMR_EOF is present even when a palette is not
available.
Description string
Have you ever just wanted to know what was in a given metafile
without having to decipher a cryptic filename or play back the
entire metafile? The enhanced metafile provides an optional
description string that provides exactly this information. In
addition to a descriptive name, the string specifies the name of
the application that created the picture. The string must contain
a null character between the application name and the picture
name. It must terminate with two null characters; for example,
"ACME Inc.\0Rocket Skates\0\0", where \0 represents the null
character. If lpDescription is NULL, there is no corresponding
entry in the header of the enhanced metafile. If the description
string is present, it is found offDescription bytes from the
beginning of the ENHMETAHEADER structure. The array found at
that offset contains nDescription characters. A convenient way
to obtain the description string is to use the function
GetEnhMetaFileDescription.
Color palette
When a palette was required in a Windows metafile, you
recorded a CreatePalette, SelectPalette, and RealizePalette
sequence. When the Windows metafile was played back, the
palette was selected as a foreground palette. The realization of
the foreground palette typically resulted in odd screen behavior
as the other palettes went to the background. With the enhanced
metafiles, palette sequences may still be recorded, but they are
never selected and realized as foreground palettes when they are
subsequently played back. These palette functions serve only to
build the metafile palette. Enhanced metafiles place this optional
palette in the metafile end-of-file record (EMR_EOF). Although
the palette is optional, there are advantages to using it. One
palette may be generated and used for the duration of the
playback, thus avoiding the problems associated with foreground
and background palette changes. The optional palette also
makes it easier for a palette-oriented application to examine the
metafile colors and merge them with an existing palette. The
easiest way to get the palette is to call
GetEnhMetaFilePaletteEntries. However, you can locate the
palette yourself if you wish. First, determine whether there is a
palette. This is done by examining nPalEntries in the enhanced
metafile header or in the last record of the metafile, the
EMR_EOF record (see code below).
typedef struct tagEMREOF
{
EMR emr; // Base enhanced metafile record.
DWORD nPalEntries; // Number of palette entries.
DWORD offPalEntries; // Offset to the palette entries.
DWORD nSizeLast; // Same as emr.nSize and must be the
// last DWORD of the record. The palette
// entries, if they exist, precede this field.
} EMREOF;
If this value is greater than zero, a palette is present. The
nSizeLast member of the EMR_EOF record indicates how many
bytes to seek back to find the beginning of the EMR_EOF record.
Seek forward from this point by offPalEntries and bingo! you
have a palette location. After having used either method to obtain
the palette, you can simply select the palette into the destination
DC, realize it, and then play back the metafile.
Device Independence
Achieving device independence was very difficult, if not
impossible, with Windows metafiles. The placeable variant of the
Windows metafile provided the best shot at this. The additional
header provided in the placeable metafile (see code below)
provided an opportunity for an application to render these
metafiles in a device-relative way.
typedef struct tagPLACEABLEMETAFILEHEADER {
DWORD key;
HANDLE hmf;
RECT bbox;
WORD inch;
DWORD reserved;
WORD checksum;
} PLACEABLEMETAFILEHEADER;
Device independence was typically achieved by setting the
mapping mode to anisotropic, setting the viewport extents to the
physical dimensions of the device, and finally setting the
windows extents to the product of the device's physical
dimensions (in inches) and the metafile units per inch (contained
in the inch member of the header structure). The biggest problem
with this approach was that variants of the placeable Windows
metafile began surfacing. Often the mapping mode and viewport
extents were included in the metafile as records. This
necessitated enumerating the metafile as a method of filtering
out undesirable records. Unfortunately, the bounding box and
metafile units per inch often did not match the environment being
set by the undesirable metafile records! This led to the situation
in which even the placeable metafiles were, once again,
application-specific.
Device independence is a key feature of enhanced metafiles. The
Microsoft Win32 Software Development Kit (SDK) for Windows
NT Programmer's Reference: Overviews states that "...when an
application creates a picture measuring 2 inches by 4 inches on
a VGA display and stores that picture in a metafile, it (the
picture) will maintain those original dimensions when it is printed
on a 300 dpi laser printer or copied over a network and displayed
in another application that is running on an 8514/A video
display." So, just how is this done? The key to achieving this
device independence is the use of a reference device context,
that is, the context of the device on which the picture was
created. When a metafile is created, information regarding the
reference DC is placed in the enhanced metafile header. More
specifically, GDI calls GetDeviceCaps and assigns the
HORZSIZE and VERTSIZE return values to szlMillimeters and
assigns the HORZRES and VERTRES return values to szlDevice
. The rclFrame member is assigned the bounding rectangle
specified in the lpRect parameter of CreateEnhMetaFile. If
lpRect is NULL, GDI determines the bounding rectangle and
assigns it to rclFrame. This information is sufficient to
enable
the playback functions to provide device independence. When a
metafile is played back, the picture undergoes a series of
transformations that scale and translate the picture to the output
rectangle that was specified in the call to the PlayEnhMetaFile
or EnumEnhMetaFile playback functions. These
transformations rely on the dimensions of the picture frame
(
rclFrame), the dimensions of the device upon which the metafile
was created (szlMillimeters and szlDevice), and the
world-to-page transform values currently set in the
destination DC.
Compatibility
Although it is not recommended, Windows metafiles can be used
with Win32-based applications. Unfortunately, enhanced
metafiles cannot be used in Windows version 3.x. The Win32 API
provides these familiar-sounding functions that manipulate
Windows metafiles:
CloseMetaFile Closes a Windows metafile DC.
CopyMetaFile Copies a Windows metafile.
CreateMetaFile Creates a Windows metafile DC.
DeleteMetaFile Invalidates Windows metafile handle.
EnumMetaFile Returns GDI calls within a Windows metafile.
EnumMetaFileProc Processes metafile data.
GetMetaFile Creates a Windows metafile.
GetMetaFileBitsEx Copies Windows metafile bits to a buffer.
PlayMetaFile Plays a Windows metafile to a DC.
PlayMetaFileRecord Plays a Windows metafile record.
SetMetaFileBitsEx Creates a memory-based Windows metafile from data.
GetMetaFileBits Obsolete; use GetMetaFileBitsEx.
SetMetaFileBits Obsolete; use SetMetaFileBitsEx.
In addition to providing functions that enable the use of Windows
metafiles, the Win32 API also provides functions to convert
Windows metafiles into enhanced metafiles. These include the
following functions:
GetWinMetaFileBits Retrieves enhanced metafile contents in Windows format.
SetWinMetaFileBits Creates enhanced metafile from Windows metafile data.
Pulling It All Together
At this point, the differences between a Windows metafile and an
enhanced metafile should be clear:
* The enhanced metafile header is larger and more complete
than a Windows metafile.
* The enhanced metafile may contain a description string or a
palette.
* The enhanced metafile achieves device independence by
means of a reference DC and special transformations in the
playback functions.
A quick look at the enhanced metafile functions and some
example code should help clarify the features of enhanced
metafiles.
Enhanced Metafile Functions
The following functions are very similar to the functions used for
Windows metafiles. The differences that exist do so to
accommodate new features of enhanced metafiles.
CloseEnhMetaFile Closes an enhanced metafile DC.
CopyEnhMetaFile Copies an enhanced metafile.
CreateEnhMetaFile Creates an enhanced metafile DC.
DeleteEnhMetaFile Invalidates enhanced metafile handle.
EnhMetaFileProc Processes enhanced metafile data.
EnumEnhMetaFile Returns GDI calls within an enhanced metafile.
GdiComment Adds a comment to an enhanced metafile.
GetEnhMetaFile Creates an enhanced metafile.
GetEnhMetaFileBits Copies enhanced metafile bits to a buffer.
GetEnhMetaFileDescription Returns creator and title for enhanced metafile.
GetEnhMetaFileHeader Returns enhanced metafile header.
GetEnhMetaFilePaletteEntries Returns enhanced metafile palette entries.
PlayEnhMetaFile Plays an enhanced metafile to a DC.
PlayEnhMetaFileRecord Plays an enhanced metafile record.
SetEnhMetaFileBits Creates a memory-based enhanced metafile from data.
GdiComment
GdiComment deserves a little elaboration. When a comment
was needed in a Windows metafile, the MFCOMMENT printer
escape was used. These comments were restricted to private
data only. The MFCOMMENT printer escape cannot be used in
enhanced metafiles. Escapes, in general, cannot be used in
enhanced metafiles because they would introduce device
dependence, which is in direct opposition to the goal of device
independence. Realizing that there is still a place for private data
in metafiles, the architects of the Win32 API made GdiComment
available for embedding private information in enhanced
metafiles. But GdiComment is more than simply an alternative
to MFCOMMENT. It was designed to enable public comments as
well. The currently supported public comments include:
GDICOMMENT_WINDOWS_METAFILE
GDICOMMENT_BEGINGROUP
GDICOMMENT_ENDGROUP
GDICOMMENT_MULTIFORMATS
The use of public comment permits embedding of other metafiles
and encapsulated PostScript (EPS) files within the metafile. The
multiformat public comment is the most exciting of the
comments. (I must be losing touch with reality!) If an EPS file is
embedded in an enhanced metafile and subsequently played
back, GDI will select the best format for the device!
Transparently! When I first heard about the multiformat comment,
I was sure that I was going to be expending a great deal of effort
writing code for rendering EPS files. I was relieved to find
out how wrong I was!
Coding Examples
The example code in the following sections demonstrates the
creation and playback of an enhanced metafile, illustrating how
some of these functions are used. (These examples are
pared-down versions of examples in the Win32 documentation.)
Creating an enhanced metafile
Creating an enhanced metafile is similar to creating a Windows
metafile. The code that follows demonstrates the creation of an
enhanced metafile that is stored on a disk. The example uses a
device context for the application window as the reference DC.
The dimensions of the application's client area are used to define
the dimensions of the picture frame. Using the rectangle
dimensions returned by the GetClientRect function, the example
converts the device units to .01-millimeter units and passes the
converted values to the CreateEnhMetaFile function. The
example also embeds a text description of the picture in the
header of the enhanced metafile.
// Obtain a handle to a reference DC.
hdcRef = GetDC(hWnd);
// Determine the picture frame dimensions.
// iWidthMM is the display width in millimeters.
// iHeightMM is the display height in millimeters.
// iWidthPels is the display width in pixels.
// iHeightPels is the display height in pixels.
iWidthMM = GetDeviceCaps(hdcRef, HORZSIZE);
iHeightMM = GetDeviceCaps(hdcRef, VERTSIZE);
iWidthPels = GetDeviceCaps(hdcRef, HORZRES);
iHeightPels = GetDeviceCaps(hdcRef, VERTRES);
// Use iWidthMM, iWidthPels, iHeightMM, and iHeightPels to determine the
// number of .01-millimeter units per pixel in the x and y directions.
iMMPerPelX = (iWidthMM * 100)/iWidthPels;
iMMPerPelY = (iHeightMM * 100)/iHeightPels;
// Retrieve the coordinates of the client rectangle in pixels.
GetClientRect(hWnd, &rect);
// Convert client coordinates to .01-mm units.
rect.left = rect.left * iMMPerPelX;
rect.top = rect.top * iMMPerPelY;
rect.right = rect.right * iMMPerPelX;
rect.bottom = rect.bottom * iMMPerPelY;
// Create the metafile DC.
hdcMeta = CreateEnhMetaFile(hdcRef,
(LPTSTR)"MYFILE.EMF", &rect,
(LPSTR)"ACME
Inc.\0Rocket Skates\0\0");
if (!hdcMeta)
errhandler("CreateEnhMetaFile", hWnd);
// Release the reference DC.
ReleaseDC(hWnd, hdcRef);
Playing an enhanced metafile
Playing an enhanced metafile is also similar to the method used
to play Windows metafiles. The following example demonstrates
how to open an enhanced metafile stored on disk, and displays
the associated picture in the client area. The example passes
the handle returned by the GetEnhMetaFile function to the
PlayEnhMetaFile function in order to display the picture. Before
diving into the code, consider the following advice about
enumeration of the metafile and some tips on how to maximize
the advanced features of the GDI metafile player.
Using EnumEnhMetaFile
It's common practice to enumerate Windows metafiles, rather
than simply to play them back, to achieve better control over
positioning, scaling, getting access to application-specific
comments, or manipulating the palette records. However, the
improvements to enhanced metafiles reduce the need for
enumeration of the metafile. In Win32, most applications need to
use only PlayEnhMetaFile unless they need to edit the
enhanced metafile by adding, deleting or modifying records, in
which case they'd use EnumEnhMetaFile.
Advanced features
Three advanced features of enhanced metafiles require action by
the application before playing the metafile to the
destination DC:
Advanced palette functionality
Advanced clipping capabilities
World-to-page transform values
The advanced palette functionality provides a means of
examining the palette before playing the metafile. This is useful if
the palette is to be merged with another or optimized before the
enhanced metafile is played or enumerated. If the metafile palette
is to be used, it must be retrieved
(GetEnhMetaFilePaletteEntries), manipulated as desired,
created, selected, and realized in the destination DC.
The advanced clipping capabilities permit the enhanced metafile
to be clipped to a predetermined clipping region. To accomplish
this, the metafile player determines if a clipping region exists in
the destination DC. If a clipping region exists, the region is
applied to the metafile contents as they are played. To use the
clipping feature, create and select any clipping regions into the
destination DC prior to playing the metafile.
Finally, the metafile player applies world-to-page transform values
set in the destination DC to the contents of the enhanced
metafile. If any scaling, rotation, reflection, or shearing is desired,
set the world-to-page transform value in the destination DC before
playing the metafile:
hemf =
GetEnhMetaFile((LPSTR)"MYFILE.EMF");
// Open the metafile.
hDC = GetDC(hWnd); // Retrieve a handle to a window DC.
GetClientRect(hWnd, &rect); // Retrieve the client rectangle dimensions.
PlayEnhMetaFile(hDC, hemf, &rect); // Draw the picture.
DeleteEnhMetaFile(hemf); // Release the metafile handle.
ReleaseDC(hWnd, hDC); // Release the window DC.
Summary
Enhanced metafiles are a giant step beyond the Windows
metafile. An expanded metafile header, a description string, a
palette, device independence, and ease of porting from the
Windows metafile format make enhanced metafiles an offer you
can't refuse! It is expected that the advanced features of
enhanced metafiles will make the use of metafiles more
acceptable than Windows metafiles. With the features listed
below, it is easy to understand why enhanced metafiles will
become an invaluable tool for Win32-based applications:
* Full transformation support (removes scaling restrictions
found in Windows metafiles)
* Unrestricted clipping capabilities
* Improved palette support
* Query support (as in GetViewportExtent and GetCurrentPositionEx)
* Advanced embedding features (metafiles and EPS files)
Probably the most important point to make about enhanced
metafiles is that there is very little reason to enumerate the
metafile. The playback code is smarter and does much of what
developers have had to do themselves by means of enumeration
for years.