2009-11-25 10:37:56| 分类: DC|Gdi|Gdi+ | 标签: |举报 |字号大中小 订阅
一、 wmf格式是什么?
---- Wmf是Windows Metafile 的缩写,简称图元文件,它是微软公司定义的一种Windows平台下的图形文件格式。我们先来解释几个名词:
---- 图元文件头(metafile header): 是一个数据结构,它定义了储存在图元文件中图象的尺寸、图元文件的大小、调色板的数目、图元文件中记录数、指向图元文件描述的指针(如果存在的话)、指向图元文件调色板的指针(如果存在的话)。
---- 图元文件设备上下文(metafile DC): 是一个用户图元文件操作的设备上下文。
---- 图元文件句柄表(metafile handle table): 是标识用来建立存储在图元文件中的笔、刷子、字体以及其它对象的一组句柄。
---- 图元文件调色板(metafile palette): 是一组红、绿、蓝的值,这些值表示建立存储在图元文件中的图象时所使用的颜色。
---- 图元文件记录(metafile record): 是一个可变长的结构,结构中包含了诸如建立图象时设备的分辨率、图象的大小以及建立图象时所需要的GDI函数。
---- 有了上面的概念,我们就可以给wmf格式文件一个定义:
---- 图元文件是一个以二进制编码的、设备无关格式的多个结构的集合,这些结构包括图元文件头、调色板(可选的)、图元文件内容的文本描述(可选的)、图元文件记录。
---- 图元文件分为内存图元文件和磁盘图元文件。内存图元文件是仅在内存某一个区域进行操作并存放的,大多用于图象的绘制、拷贝或者进程间的剪切板图形共享;磁盘图元文件则主要用于将绘制图象保存到磁盘文件中,以便事后重看。
---- 二、 wmf格式的特点
---- wmf格式文件的特点如下:
---- 1. wmf格式文件是Microsoft Windows操作平台所支持的一种图形格式文件,目前,其它操作系统尚不支持这种格式,如Unix、Linux等。
---- 2. 与bmp格式不同,wmf格式文件是设备无关的,即它的输出特性不依赖于具体的输出设备。
---- 3. 其图象完全由Win32 API所拥有的GDI函数来完成。
---- 4. wmf格式文件所占的磁盘空间比其它任何格式的图形文件都要小得多。
---- 5. 在建立图元文件时,不能实现即画即得,而是将GDI调用记录在图元文件中,之后,在GDI环境中重新执行,才可显示图象。
---- 6. 显示图元文件的速度要比显示其它格式的图象文件慢,但是它形成图元文件的速度要远大于其它格式。
---- 三、 wmf格式的应用场合
---- 由图元文件的特点,可知图元文件与其它格式的图象文件差别很大。
---- 首先,由于图元文件是以图象绘制操作序列来存放数据的,因此,它不适合于图象处理领域;其次,由于图元文件的图象显示速度慢,因此也不适合于需要快速显示的场合。
---- 但是,微软之所以设计了这种格式,自然有它独特的地方,这就是wmf格式文件所占的磁盘空间比其它任何格式的图形文件都要小得多。也就是说,只要用对场合,只这一条,便可击败所有格式无对手。
---- 一般地,图元文件的适用场合如下:
---- 1. 由采集数据绘制曲线的图象快速保存。
---- 2. 进程间的图象剪切板数据交换。
其实,wmf格式也有着它独特的优越性
关于应用实例
1. 功能设计
---- (1) 建立图元文件 为减少程序篇幅,这里假设将产生的图元文件保存到一指定的文件名Myfile.wmf,另外,将图形假设为一正弦波。
---- (2) 显示图元文件 打开图元文件MyFile.wmf,将刚才产生的图形恢复到显示器上。
---- 2. 软件结构
---- 在Windows 98平台下,采用Visual C++ 6.0 开发工具,其软件结构使用MFC的单文档(SDI)框架。
---- 3. 程序实现
---- (1) 使用MFC AppWizard向导产生一应用框架
---- 在VC++的“File”菜单中,单击“New”,弹出一New对话框。在“Projects”页中选择“MFC AppWizard [exe]”,在“Project name”编辑框中填入“MyWMF”,按“OK”按钮,退出New对话框。
---- 在“MFC AppWizard Step 1”对话框中选择单选钮“Single document”,按“Finish”按钮即可完成应用框架的定制。
---- (2) 在视类的头文件MyWMFView.h中增加成员变量
---- HMETAFILE m_hMetaFile;
---- (3) 增加“建立图元文件”和“显示图元文件”菜单
---- 在“ResourceView”中,双击“Menu”下的“IDR_MAINFRAME”,在右边的窗口里,增加菜单“建立图元文件”,其标识为“ID_CREATEMETAFILE”;增加菜单“显示图元文件”,其标识为“ID_DISPMETAFILE”。
---- (4) 增加两个菜单所对应的消息处理函数
---- 在VC++的“New”菜单中,单击“ClassWizard”,弹出一“MFC ClassWizard”对话框。在“Class Name”组合框中选择“CMyWMFView”,在“Object IDs”列表框中选择“ID_CREATEMETAFILE”,在右边的“Messages”列表框中双击“COMMAND”,之后弹出一对话框,点击 “OK”按钮,即建立了一个消息处理函数“On
---- (5) 在视类的执行文件MyWMFView.cpp的开始中增加头文件定义
---- #include “math.h”
---- (5) 在消息处理函数“On
----
//类CMetaFileDC的实例化
CMetaFileDC metaFileDC;
//建立图元的输出文件
metaFileDC.Create("MyFile.wmf");
//设置文本颜色和笔颜色
metaFileDC.SetTextColor(RGB(255,0,0,));
CPen thePen(PS_SOLID,1,RGB(0,0,255,));
CPen * pOldPen=metaFileDC.SelectObject(&thePen);
//在图元文件中绘制矩形框
metaFileDC.Rectangle(15, 15, 530, 230);
//在图元文件中绘制正弦波
for (int i=1; i< 500; i++)
{
metaFileDC.MoveTo(20+i-1, 120-80*sin(0.1*(i-1)));
metaFileDC.LineTo(20+i, 120-80*sin(0.1*i));
}
//在图元文件中绘制文本
metaFileDC.TextOut(200,250,"图6
电机载荷正弦波曲线图");
//恢复缺省的笔
metaFileDC.SelectObject(pOldPen);
//将以上绘制写入图元文件MyFile.wmf,关闭之,
最后返回图元文件的句柄
m_hMetaFile = metaFileDC.Close();
(6) 在消息处理函数“On
//定义一个客户区设备上下文,用于显示图元文件
CClientDC clientDC(this);
//打开图元文件,返回图元文件句柄
HMETAFILE hmf=GetMetaFile("MyFile.wmf”);
//显示图元文件,再现所绘制的曲线
clientDC.PlayMetaFile(hmf);
---- (7) 经过编译、链接,形成可执行文件 MyWMF.exe。
---- 使用时先点击菜单“建立图元文件”,即可发现,在当前文件夹下,生成一个新文件MyFile.wmf;然后,再点击菜单“显示图元文件”,即可在客户区显示一幅正弦波曲线。
---- 五、 结束语
----虽然WMF格式其结构定义比较复杂,但通过上面的编程实践,可见其实现起来并不复杂。这主要得力于MFC将内部复杂的处理封装在CMetaFileDC类中,对这个类的正确使用,即可达到事半功倍的效果。另外,我们在比较某某图象格式时,不能一言以蔽之,武断地说某某好某某不好,而应该结合具体的应用场合。
图元文件并不是矢量图,因为它存储的并不是矢量信息。
它存储的是你在绘图的时候调用了哪些操作。
如果是位图文件记录了你的画布上每一点的颜色的话,
图元文件就是纪录的你如何下笔的。
所谓的矢量图纪录的是矢量信息,也就是说只要知道矢量文件的格式,
在任何环境下(比如说不同的操作系统)都可以使用,
但是图元文件必须依赖于windows系列操作系统的绘图函数
——————————————————————————————————————————
MetaFile和向量图形的关系,就像位图和位映像图形的关系一样。位图通常来自实际的图像,而MetaFile则大多是通过计算机程序人为建立的。MetaFile由一系列与图形函数呼叫相同的二进制记录组成,这些记录一般用于绘制直线、曲线、填入的区域和文字等。
「画图(paint)」程序建立位图,而「绘图(draw)」程序建立MetaFile。在优秀的绘图程序中,能轻易地「抓住」某个独立的图形对象(例如一条直线)并将它移动到其它位置。这是因为组成图形的每个成员都是以单独的记录储存的。在画图程序中,这是不可能的-您通常都会局限于删除或插入位图矩形块。
由于MetaFile以图形绘制命令描述图像,因此可以对图像进行缩放而不会失真。位图则不然,如果以二倍大小来显示位图,您却无法得到二倍的分辨率,而只是在水平和垂直方向上重复位图的位。
MetaFile可以转换为位图,但是会丢失一些信息:组成MetaFile的图形对象将不再是独立的,而是被合并进大的图像。将位图转换为MetaFile要艰难得多,一般仅限于非常简单的图像,而且它需要大量处理来分析边界和轮廓。而MetaFile可以包含绘制位图的命令。
虽然MetaFile可以作为图片剪辑储存在磁盘上,但是它们大多用于程序通过剪贴簿共享图片的情况。由于MetaFile将图片描述为图像函数呼叫的集合,因而它们既比位图占用更少的空间,又比位图更与设备无关。
Microsoft Windows支持两种MetaFile格式和支持这些格式的两组函数。我首先讨论从Windows 1.0到目前的32位Windows版本都支持的MetaFile函数,然后讨论为32位Windows系统开发的「增强型MetaFile」。增强型MetaFile在原有MetaFile的基础上有了一些改进,应该尽可能地加以利用。
旧的 MetaFile 格式
MetaFile既能够暂时储存在内存中,也能够以文件的形式储存在磁盘上。对应用程序来说,两者区别不大,尤其是由Windows来处理磁盘上储存和加载MetaFile资料的文件I/O时,更是如此。
内存MetaFile的简单利用
如果呼叫CreateMetaFile函数来建立MetaFile设备内容,Windows就会以早期的格式建立一个MetaFile,然后您可以使用大部分GDI绘图函数在该MetaFile设备内容上进行绘图。这些GDI呼叫并不在任何具体的设备上绘图,相反地,它们被储存在MetaFile中。当关闭MetaFile设备内容时,会得到MetaFile的句柄。这时就可以在某个具体的设备内容上「播放」这个MetaFile,这与直接执行MetaFile中GDI函数的效果等同。
CreateMetaFile只有一个参数,它可以是NULL或文件名称。如果是NULL,则MetaFile储存在内存中。如果是文件名称(以.WMF作为「Windows MetaFile」的扩展名),则MetaFile储存在磁盘文件中。
程序18-1中的MetaFile显示了在WM_CREATE消息处理期间建立内存MetaFile的方法,并在WM_PAINT消息处理期间将图像显示100遍。
程序18-1 MetaFile
MetaFile.C /*------------------------------------------------------------------------- MetaFile.C -- MetaFile Demonstration Program (c) Charles Petzold, 1998 --------------------------------------------------------------------------*/ #include <windows.h> LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName [] = TEXT ("MetaFile") ; HWND hwnd ; MSG msg ; WNDCLASS wndclass ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; if (!RegisterClass (&wndclass)) { MessageBox ( NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ; return 0 ; } hwnd = CreateWindow (szAppName, TEXT ("MetaFile Demonstration"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ; ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; } LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam) { static HMetaFile hmf ; static int cxClient, cyClient ; HBRUSH hBrush ; HDC hdc, hdcMeta ; int x, y ; PAINTSTRUCT ps ; switch (message) { case WM_CREATE: hdcMeta= CreateMetaFile (NULL) ; hBrush= CreateSolidBrush (RGB (0, 0, 255)) ; Rectangle (hdcMeta, 0, 0, 100, 100) ; MoveToEx (hdcMeta, 0, 0, NULL) ; LineTo (hdcMeta, 100, 100) ; MoveToEx (hdcMeta, 0, 100, NULL) ; LineTo (hdcMeta, 100, 0) ; SelectObject (hdcMeta, hBrush) ; Ellipse (hdcMeta, 20, 20, 80, 80) ; hmf = CloseMetaFile (hdcMeta) ; DeleteObject (hBrush) ; return 0 ; case WM_SIZE: cxClient = LOWORD (lParam) ; cyClient = HIWORD (lParam) ; return 0 ; case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; SetMapMode (hdc, MM_ANISOTROPIC) ; SetWindowExtEx (hdc, 1000, 1000, NULL) ; SetViewportExtEx (hdc, cxClient, cyClient, NULL) ; for (x = 0 ; x < 10 ; x++) for (y = 0 ; y < 10 ; y++) { SetWindowOrgEx (hdc, -100 * x, -100 * y, NULL) ; PlayMetaFile (hdc, hmf) ; } EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY: DeleteMetaFile (hmf) ; PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; }
这个程序展示了在使用内存MetaFile时所涉及的4个MetaFile函数的用法。第一个是CreateMetaFile。在WM_CREATE消息处理期间用NULL参数呼叫该函数,并传回MetaFile设备内容的句柄。然后,MetaFile利用这个MetaFileDC来绘制两条直线和一个蓝色椭圆。这些函数呼叫以二进制形式储存在MetaFile中。CloseMetaFile函数传回MetaFile的句柄。因为以后还要用到该MetaFile句柄,所以把它储存在静态变量。
该MetaFile包含GDI函数呼叫的二进制表示码,它们是两个MoveToEx呼叫、两个LineTo呼叫、一个SelectObject呼叫(指定蓝色画刷)和一个Ellipse呼叫。坐标没有指定任何映像方式或转换,它们只是作为数值数据被储存在MetaFile中。
在WM_PAINT消息处理期间,MetaFile设定一种映像方式并呼叫PlayMetaFile在窗口中绘制对象100次。MetaFile中函数呼叫的坐标按照目的设备内容的目前变换方式加以解释。在呼叫PlayMetaFile时,事实上是在重复地呼叫最初在WM_CREATE消息处理期间建立MetaFile时,在CreateMetaFile和CloseMetaFile之间所做的所有呼叫。
和任何GDI对象一样,MetaFile对象也应该在程序终止前被删除。这是在WM_DESTROY消息处理期间用DeleteMetaFile函数处理的工作。
评论