1第11章GDI编程4—图元文件与打印图元文件是一种矢量图形文件,用于绘图指令序列的文件存储和播放再现。与点阵图像相比,图形文件所占的空间小,且可任意缩放而不产生马赛克效应,但是绘制图形需要一定的时间。图元文件还可用于交互绘图中的图形重绘和图形软件中的图元编辑。GDI除了支持图形的屏幕绘制外,也支持图形的打印输出。使用传统的API进行Windows的打印编程,异常复杂和艰难。而MFC对打印功能的封装,大大简化了程序员的打印编程工作。本章将对使用MFC进行图元文件和打印编程的具体方法分别做一些简单介绍。11.1图元文件GDI从一开始就支持(图)元文件(metafile),早期(1985年起)的版本为WMF(WindowsMetaFile,视窗元文件),主要针对Win16(Win3.x),后来(1990年起)也支持Win32(Win95/98/Me)。以后(1993年)随WindowsNT推出了改进的图元文件版本——EMF(EnhancedWindowsMetaFile,增强型视窗元文件),只支持Win32(Win95/98/Me/NT/2000/XP/Vista/7)。现在(2001年起)又随WindowsXP和GDI+推出了加强型图元文件EMF——EMF+,可以同时支持GDI和GDI+。表11-1图元文件所支持的GDI类型元文件类型Win16GDIWin32GDIWin32/64GDI+WMF√√×EMF×√×EMF+×√√本节只介绍GDI中的图元文件格式WMF和EMF,重点介绍在MFC中使用图元文件。至于GDI+中的图元文件格式EMF+和如何在GDI+编程中使用图元文件及其相关类,将在14.4节中介绍。11.1.1图元文件格式下面分别介绍WMF和EMF的具体文件格式。21.WMF文件格式元文件结构——WMF文件由文件头和若干元文件记录组成,参见图11-1。视窗元文件头元文件记录……图11-1WMF的文件结构元文件头——WMF的文件头用结构METAHEADER定义:typedefstructtagMETAHEADER{WORDmtType;//元文件类型:内存=0、磁盘文件=1WORDmtHeaderSize;//文件头大小的字数WORDmtVersion;//系统的版本号:支持DIB=0x0300、不支持DIB=0x0100DWORDmtSize;//文件大小的字数WORDmtNoObjects;//同时存在于元文件内的最大对象数DWORDmtMaxRecord;//元文件中最大记录的字大小WORDmtNoParameters;//保留字段}METAHEADER;元文件记录——WMF的元文件记录用结构METARECORD定义:typedefstructtagMETARECORD{DWORDrdSize;//记录大小的字数WORDrdFunction;//功能/函数号(记录类型META_XXX)WORDrdParm[1];//函数参数数组,逆序排列}METARECORD;WMF中的图元文件记录类型共有67种,包含所有的绘图设置和操作(DC函数),例如:设置二元光栅操作(符号常量META_SETROP2,对应数值0x0104)、绘制矩形(META_RECTANGLE,0x041B)和输出文本(META_TEXTOUT,0x0521)等。2.EMF文件格式元文件结构——EMF文件由文件头、可选的描述串和调色板、及若干元文件记录组3成,参见图11-2。增强型元文件头[描述串][调色板]元文件记录……图11-2EMF的文件结构元文件头——EMF的文件头用结构ENHMETAHEADER定义(比WMF的复杂得多):typedefstructtagENHMETAHEADER{DWORDiType;//记录类型,必须=EMR_HEADER(=1)DWORDnSize;//结构的字节大小,可能sizeof(ENHMETAHEADER)RECTLrclBounds;//边界矩形(设备单位,含右边和底边)RECTLrclFrame;//边界矩形(0.01毫米单位HIMETRIC,含右边和底边)DWORDdSignature;//签名,必须=ENHMETA_SIGNATURE(=0x464D4520)DWORDnVersion;//元文件版本,当前=0x10000DWORDnBytes;//元文件的字节大小DWORDnRecords;//元文件中的记录数WORDnHandles;//元文件句柄表中的句柄数(第0个句柄被保留)WORDsReserved;//保留,必须=0DWORDnDescription;//描述字符数组中的字符数,无描述串时必须设为0DWORDoffDescription;//描述串相对于文件头开始处的偏移量,无描述串时必须设为0DWORDnPalEntries;//元文件内调色板中的表项数SIZELszlDevice;//以像素为单位的参考设备分辨率SIZELszlMillimeters;//以毫米为单位的参考设备分辨率#if(WINVER=0x0400)//Win95/WinNT4.0以上DWORDcbPixelFormat;//像素格式,无像素格式设置时=0、4//开始设置为DC时=size0f(PIXELFORMATDESCRIPTOR)、//有多个单像素格式设置时=指向最后一个像素格式头的指针DWORDoffPixelFormat;//像素格式的偏移量DWORDbOpenGL;//元文件中是否包含OpenGL记录#endif/*WINVER=0x0400*/#if(WINVER=0x0500)//Win98/Win2000以上SIZELszlMicrometers;//以微米表示的参考设备大小#endif/*WINVER=0x0500*/}ENHMETAHEADER;其中:typedefstruct_RECTL{LONGleft;LONGtop;LONGright;LONGbottom;}RECTL;typedefstructtagSIZE{LONGcx;LONGcy;}SIZE;typedefSIZESIZEL;元文件记录——EMF的元文件记录用结构ENHMETARECORD定义(与WMF的METARECORD类似,只是交换了大小和类型的顺序):typedefstructtagENHMETARECORD{DWORDiType;//记录类型(功能/函数号EMR_XXX)DWORDnSize;//记录的字节大小DWORDdParm[1];//传递给GDI函数的参数数组}ENHMETARECORD;EMF中的图元文件记录类型共有121种(几乎是WMF的两倍),包含Win32GDI的所有绘图设置和操作,还包含若干兼容16位GDI的DC函数。例如:设置二元光栅操作(符号常量EMR_SETROP2,对应数值20)、绘制矩形(EMR_RECTANGLE,43)、输出文本(EMR_EXTTEXTOUTW,84)和绘制多边形(EMR_POLYPOLYGON/EMR_POLYPOLYGON16,8/91)等。11.1.2图元文件的MFC编程可以直接利用WindowsSDK中的有关API函数进行图元文件编程,但是限于篇幅,这里只介绍如何利用MFC的CMetaFileDC类进行图元文件的编程。CMetaFileDC是CDC的派生类,是对图元文件功能的封装。CMetaFileDC类很简单,只有一个默认构造函数——CMetaFileDC、两个具体创建函数5——Create(创建WMF)和CreateEnhanced(创建EMF)、两个关闭函数——Close(关闭WMF)和CloseEnhanced(关闭EMF),其他主要是使用其父类CDC的成员函数。1.创建CMetaFileDC对象创建CMetaFileDC对象分两步进行,首先调用CMetaFileDC类的唯一(默认)构造函数来构造一个空对象,然后再调用该类的Create成员函数来创建一个WMF图元文件对象、或调用CreateEnhanced成员函数来创建一个EMF图元文件对象。下面是这些函数的原型:CMetaFileDC();BOOLCreate(LPCTSTRlpszFilename=NULL);BOOLCreateEnhanced(CDC*pDCRef,LPCTSTRlpszFileName,LPCRECTlpBounds,LPCTSTRlpszDescription);其中:pDCRef——参考DC,一般取为当前视图类的指针。为NULL时,使用当前显示设备作为参考DC。lpszFilename——图元文件名串的指针,如果为NULL,则创建内存图元文件。lpBounds——边界矩形(单位是0.01毫米),可以是RECT结构或CRect对象的指针。为NULL时,取包含用户图形的最小矩形。lpszDescription——描述字符串,一般包含应用程序名和图名,也可以为NULL。例如:CMetaFileDCmetaDC;//构造元文件DC空对象//metaDC.Create(NULL);//创建内存WMF元文件DC//metaDC.Create(Ltest.wmf);//创建WMF元文件DC//创建内存EMF元文件DC//metaDC.CreateEnhanced(NULL,NULL,NULL,NULL);//获取屏幕大小HDChdcRef=GetDC()-m_hDC;intiWidthMM=GetDeviceCaps(hdcRef,HORZSIZE);//屏幕宽(毫米)intiHeightMM=GetDeviceCaps(hdcRef,VERTSIZE);//屏幕高(毫米)intiWidthPels=GetDeviceCaps(hdcRef,HORZRES);//屏幕宽(像素)6intiHeightPels=GetDeviceCaps(hdcRef,VERTRES);//屏幕高(像素)//获取客户区大小,并将像素坐标转换为0.01毫米坐标RECTrect;GetClientRect(&rect);//像素坐标rect.right=(rect.right*iWidthMM*100)/iWidthPels;rect.bottom=(rect.bottom*iHeightMM*100)/iHeightPels;metaDC.CreateEnhanced(GetDC(),Ltest.emf,&rect,LMFCDrawMixGraphics);//创建EMF元文件DC2.添加绘图记录因为CMetaFileDC是CDC的派生类,可以像用普通CDC对象一样地,使用CMetaFileDC来设置绘图环境和执行绘图指令。例如:metaDC.SelectObject(pLinePen);metaDC.MoveTo(point1);metaDC.LineTo(point2);……3.播放图元文件播放图元文件是指通过重画图元文件中的所有绘图记录(执行对应的绘图函数指令)来再现整个图形。可以用CMetaFileDC和CDC类的相关成员函数来播放本程序所创建的图元文件,但是需要用WindowsSDK的相关图元函数才能装入和播放磁盘上的图元文件,还可以用CImage类来装入和显示磁盘上的图元文件。1)播放本程序所创建的图元文件为了播放在程序中创建的图元文件,必须先关闭图元文件DC,这可交由CMetaFileDC类的成员函数Close或CloseEnhanced来完成,然后用它们的返回值(图元文件的句柄)来调用CDC类的成员函数PlayMetaFile来播放图元文件。这些函数的原型如下:HMETAFILEClose();//关闭WMF图元文件DC,出错返回NULLHENHMETAFILECloseEnhanced();//关闭EMF图元文件DC,出错返回NULLBOOLPlayMetaFile(HMETAFILEhMF);//播放WMF图元文件7//播放EMF图元文件BOOLP