[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: WMF problems



> * 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.





[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index] Mail converted by Mofo Magic and the Flying D

 
All trademarks and copyrights are the property of their respective owners.

Other Directory Sites: SeekWonder | Directory Owners Forum

GuideSMACK