18.1 老式图元文件格式(wmf)

(1)创建图元文件:HDC hdcMeta = CreateMetaFile(lpszFile);

  ①如果lpszFile为NULL则图元文件存储在内存中,如果指定文件名(XXX.WMF)则存储为磁盘文件。

  ②返回值为图元文件的设备环境句柄,可以使用内存DC一样,用GDI绘图函数在其上绘图。

(2)关闭图元文件:HMETAFILE hmf= CloseMetaFile(hdcMeta);

  ①这里不像一般的DC,创建DC后要删除DC,而是关闭。

  ②关闭图元文件的设备环境会返回该图元文件的句柄。

(3)显示(绘制)图元文件:PlayMetaFile

  ①绘制图元文件中的各对象,即在CreateMetaFile和CloseMetaFile之间所有的GDI调用。

  ②图元文件中的函数坐标,其具体含义将由目标设备环境的当前坐标转换设置来确定。

(4)删除图元文件句柄:DeleteMetaFile(hmf);//

★注意只删除图元文件句柄,并没删除磁盘上的文件。要删除文件可调用DeleteFile。

【MetaFile程序】

/*------------------------------------------------------------
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 = ;
wndclass.cbWndExtra = ;
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 ;
} hwnd = CreateWindow (szAppName, // window class name
TEXT ("Metafile Demonstration"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ; while (GetMessage (&msg, NULL, , ))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
} LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{ PAINTSTRUCT ps ;
static HMETAFILE hmf;
static int cxClient, cyClient;
HDC hdc,hdcMeta;
HBRUSH hBrush;
int x, y; switch (message)
{
case WM_CREATE:
//创建图元文件设备环境(内存中)
hdcMeta = CreateMetaFile(NULL); //创建蓝色画刷
hBrush = CreateSolidBrush(RGB(, , )); Rectangle(hdcMeta, , , , ); MoveToEx(hdcMeta, , , NULL); //左上
LineTo(hdcMeta, , ); //右下
MoveToEx(hdcMeta, , , NULL);//左下
LineTo(hdcMeta, , ); //右上 SelectObject(hdcMeta, hBrush);
Ellipse(hdcMeta, , , , ); //关闭图元文件设备环境,并返回图元文件句柄
hmf = CloseMetaFile(hdcMeta); DeleteObject(hBrush);
return ; case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return ; case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ; //设置图元文件里面对象的坐标单位。
SetMapMode(hdc, MM_ANISOTROPIC);
SetWindowExtEx(hdc, , , NULL);
SetViewportExtEx(hdc, cxClient, cyClient, NULL); //重复画图元文件100次,按10*10排列
for (y = ; y < ; y++)
for (x = ; x < ; x++)
{
SetWindowOrgEx(hdc, - * x, - * y, NULL);
PlayMetaFile(hdc, hmf);
} EndPaint (hwnd, &ps) ;
return ; case WM_DESTROY:
DeleteMetaFile(hmf);
PostQuitMessage () ;
return ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
} void PrepareMetaFile(HDC hdc, LPMETAFILEPICT pmfp, int cxClient,int cyClient)
{
int xScale, yScale, iScale; SetMapMode(hdc, pmfp->mm); //根据mm字段设置映射模式 //处理MM_ISOTROPIC和MM_ANISOTROPIC情况
if (pmfp->mm == MM_ISOTROPIC || pmfp->mm == MM_ANISOTROPIC)
{
if (pmfp->xExt == ) //xExt\yExt表示不指定图像的大小时
{
//在图元文件内部己经会自己调用SetWindowExtEx函数,这里无须设置。
SetViewportExtEx(hdc, cxClient, cyClient, NULL);
}
else if (pmfp->xExt >) //xExt\yExt表示图像的大小,单位是0.01mm
{
SetViewportExtEx(hdc,
pmfp->xExt* GetDeviceCaps(hdc, HORZRES) /
GetDeviceCaps(hdc, HORZSIZE) / , //将逻辑单位转为像素大小
pmfp->yExt* GetDeviceCaps(hdc, VERTRES) /
GetDeviceCaps(hdc, VERTSIZE) / , //将yExt*0.01mm转为像素大小
NULL);
}
else if (pmfp->xExt < ) //xExt、yExt表示图像的比值表示纵横比。
{
//将图像显示区域除以图像的大小,获得缩放比
//首先cxClient的单位为像素,乘以HORZSIZE/HORZRES,转换为像素规模所对应的毫米总数,再乘以100
//转为单位为0.01毫米,最后再除以图像的大小,得到缩放比
xScale = * cxClient * GetDeviceCaps(hdc, HORZSIZE) / //单位都化为0.01毫米进行比较
GetDeviceCaps(hdc, HORZRES) / -pmfp->xExt; yScale = * cyClient * GetDeviceCaps(hdc, VERTSIZE) / //单位都化为0.01毫米进行比较
GetDeviceCaps(hdc, VERTRES) / -pmfp->yExt; iScale = min(xScale, yScale); //设置视口范围,将图像大小映射到整个显示区域
SetViewportExtEx(hdc, -pmfp->xExt *iScale* GetDeviceCaps(hdc, HORZRES) /
GetDeviceCaps(hdc, HORZSIZE) /,
-pmfp->yExt *iScale* GetDeviceCaps(hdc, VERTRES) /
GetDeviceCaps(hdc, VERTSIZE) /,
NULL);
}
} //如果不是MM_ISOTROPIC或MM_ANISOTROPIC模式,则xExt和yExt的值表示图像的宽度和
//高度,单位由mm字段的设置决定。
}

18.1.1 把图元文件存储到磁盘

(1)获取磁盘中的图元文件:hmf = GetMetaFile(szFileName);

(2)在WM_PAINT中处理完后,可以直接DeleteMetaFile(hmf);

(3)当把图元文件定义为资源时,可以将其作为一个数据块加载。如果己经有图元文件内容的数据块,可以使用如下语句来创建图元文件。

hmf = SetMetaFileBitsEx(iSize,pData);//根据pData的内容来创建图元文件。

GetMetaFileBitsEx(hmf,iSize,pData);//将图元文件拷到pData内存块中。iSize为图元文件的大小。

18.1.2 老式的图元文件和剪贴板

(1)老式图元文件的缺点:

  ①老式图元文件中的坐标是逻辑坐标。显示时,图像大小很难确定。

  ②如果在图元文件内部设置了MM_ISOTROPIC或MM_ANISOTROPIC映射模式时,那么程序在PlayMetaFile期间用户很难干预,也就不能设置映射模式了。只能在PlayMetaFile之前或之后设置映射模式了。但图元文件内部会调用SetWindowExtEx等函数,所以,用户设置的无法真正工作。

(2)解决方案——传入剪贴板的不是图元文件句柄,而是METAFILEPIC结构体。

字段

含义

LONG mm

映射模式

LONG xExt

图元文件的宽度和高度

1. 在除MM_ISOTROPIC和MM_ANISOTROPIC映射模式下,其单位为mm字段中设置映射模式的单位。

2. 在MM_ISOTROPIC和MM_ANISOTROPIC中,单位:0.01mm。

①xExt=0时,表示不指定图像的尺寸或纵横比

②xExt>0时,表示图像的宽度和高度。

③xExt<0时,其值单位仍然是0.01mm,但这种情况下,更有意义的是xExt/yExt的比值,即纵横比。

LONG yExt

LONG hMF

图元文件句柄

  注意:当得到图元文件设备环境后,要在其上绘图前,一般还用调用SetWindowExtEx来指定绘图逻辑单位。但一般不包含SetMapMode、SetViewportExtEx或SetViewportOrgEx的调用。因为这些是基于显示平面的设备单位。即图元文件本身,内部一般要调用SetWindowExtEx函数,但不包含SetViewportExtEx等函数。

(3)创建图元文件并复制到剪贴板

 //创建图元文件设备环境
hdcMeta = CreateMetaFile(NULL); //基于内存的
SetWindowExtEx(hdcMeta,…); //在图元文件内部设置映射模式,但不包含
SetWindowOrgEx(hdcMeta,…); // SetMapMode或SetViewportExtEx函数。 //获取该图元文件的句柄
hmf = CloseMetaFile(hdcMeta); //复制到剪贴板
GLOBALHANDLE hGlobal;
LPMETAFILEPICT pMFP; //指向METAFILEPICT结构的指针
hGlobal = GlobalAlloc(GHND|GMEM_SHARE,sizeof(METAFILEPICT));
pMFP = (LPMETAFILEPICT)GlobalLock(hGlobal); //设置结构体设置
pMFP->mm = MM_...; //使用的映射模式;
pMFP->xExt = …; //设置图像的宽度(逻辑单位)
pMFP->yExt =…;
pMPF->hMF = hmf; GlobalUnlock(hGlobal); //传送到剪贴板
OpenClipboard(hwnd);
EmptyClipboard();
SetClipboardData(CF_METAFILEPICT,hGlobal);//这里传入的是METAFILEPIC结构,而不是hmf;
CloseClipboard(); //至此,hGlobal和hmf句柄失效,不能再使用它们了。

(4)从剪贴板中获取图元文件,并显示。

//获取METAFILEPICT结构体
OpenClipboard(hwnd);
hGlobal = GetClipboardData(CF_METAFILEPICT);
pMFP->(LPMETAFILEPICT)GlobalLock(hGlobal); SaveDC(hdc);
//根据mm、xExt、yExt设置映射模式
PrepareMetaFile(hdc,pMFP,cxClient,cyClient); //其中cxClient,cyClient为图元文件要显示的像素宽度和高度。该函数是自定义的,见后面的代码实现。
PlayMetaFile(pMFP->hMF);
RestoreDC(hdc,-); GlobalUnlock(hGlobal);
CloseClipboard(); ()PrepareMetaFile函数的分析
void PrepareMetaFile(HDC hdc, LPMETAFILEPICT pmfp, int cxClient,int cyClient)
{
int xScale, yScale, iScale; SetMapMode(hdc, pmfp->mm); //根据mm字段设置映射模式 //处理MM_ISOTROPIC和MM_ANISOTROPIC情况
if (pmfp->mm == MM_ISOTROPIC || pmfp->mm == MM_ANISOTROPIC)
{
if (pmfp->xExt == ) //xExt\yExt表示不指定图像的大小时
{
//在图元文件内部己经会自己调用SetWindowExtEx函数,这里无须设置。
SetViewportExtEx(hdc, cxClient, cyClient, NULL);
}
else if (pmfp->xExt >) //xExt\yExt表示图像的大小,单位是0.01mm
{
SetViewportExtEx(hdc,
pmfp->xExt* GetDeviceCaps(hdc, HORZRES) /
GetDeviceCaps(hdc, HORZSIZE) / , //将逻辑单位转为像素大小
pmfp->yExt* GetDeviceCaps(hdc, VERTRES) /
GetDeviceCaps(hdc, VERTSIZE) / , //将yExt*0.01mm转为像素大小
NULL);
}
else if (pmfp->xExt < ) //xExt、yExt表示图像的比值表示纵横比。
{
//将图像显示区域除以图像的大小,获得缩放比
//首先cxClient的单位为像素,乘以HORZSIZE/HORZRES,转换为像素规模所对应的毫米总数,再乘以100
//转为单位为0.01毫米,最后再除以图像的大小,得到缩放比
xScale = * cxClient * GetDeviceCaps(hdc, HORZSIZE) / //单位都化为0.01毫米进行比较
GetDeviceCaps(hdc, HORZRES) / -pmfp->xExt; yScale = * cyClient * GetDeviceCaps(hdc, VERTSIZE) / //单位都化为0.01毫米进行比较
GetDeviceCaps(hdc, VERTRES) / -pmfp->yExt; iScale = min(xScale, yScale); //设置视口范围,将图像大小映射到整个显示区域
SetViewportExtEx(hdc, -pmfp->xExt *iScale* GetDeviceCaps(hdc, HORZRES) /
GetDeviceCaps(hdc, HORZSIZE) /,
-pmfp->yExt *iScale* GetDeviceCaps(hdc, VERTRES) /
GetDeviceCaps(hdc, VERTSIZE) /,
NULL);
}
} //如果不是MM_ISOTROPIC或MM_ANISOTROPIC模式,则xExt和yExt的值表示图像的宽度和
//高度,单位由mm字段的设置决定。
}

(5)Windows剪贴板会自动进行老格式和增强型格式之间的转换。是否转换,要看用户从剪贴板请求的文件格式。

第18章 图元文件_18.1 老式图元文件格式(wmf)的更多相关文章

  1. 第18章 图元文件_18.2 增强型图元文件(emf)(2)

    18.2.7 增强型图元文件的查看和打印程序 (1)传递EMF到剪贴板,剪贴板类型应为:CF_ENHMETAFILE (2)CopyEnhMetaFile用于复制图元文件 (3)剪贴板中的图元文件会自 ...

  2. 第18章 图元文件_18.2 增强型图元文件(emf)(1)

    18.2 增强型图元文件(emf) 18.2.1 创建并显示增强型图元文件的步骤 (1)创建:hdcEMF = CreateEnhMetaFile(hdcRef,szFilename,lpRect,l ...

  3. 第18章 集合框架(2)-Set接口

    第18章 集合框架(2)-Set接口 Set是Collection子接口,模拟了数学上的集的概念 Set集合存储特点 1.不允许元素重复 2.不会记录元素的先后添加顺序 Set只包含从Collecti ...

  4. Java 第18章 多态

    18 章  --> 多态 继承: extends 抽象类 abstract (限制类的实例化) 抽象方法 public abstract void show(); //抽象方法只有方法的声明,没 ...

  5. LPTHW 笨方法学python 18章

    看完18章以后,发现第一个练习中,使用了*args读取全部的的输入参数作为一个元组,但是在他的练习中只给了两个变量去赋值,当用户不清楚这个函数的定义时,就可能会给出过多的变量进这个函数,那么就会出现如 ...

  6. 《TCP/IP详解卷1:协议》第17、18章 TCP:传输控制协议(1)-读书笔记

    章节回顾: <TCP/IP详解卷1:协议>第1章 概述-读书笔记 <TCP/IP详解卷1:协议>第2章 链路层-读书笔记 <TCP/IP详解卷1:协议>第3章 IP ...

  7. 《TCP/IP详解卷1:协议》第17、18章 TCP:传输控制协议(2)-读书笔记

    章节回顾: <TCP/IP详解卷1:协议>第1章 概述-读书笔记 <TCP/IP详解卷1:协议>第2章 链路层-读书笔记 <TCP/IP详解卷1:协议>第3章 IP ...

  8. Linux就这个范儿 第18章 这里也是鼓乐笙箫 Linux读写内存数据的三种方式

    Linux就这个范儿 第18章  这里也是鼓乐笙箫  Linux读写内存数据的三种方式 P703 Linux读写内存数据的三种方式 1.read  ,write方式会在用户空间和内核空间不断拷贝数据, ...

  9. 【C#4.0图解教程】笔记(第9章~第18章)

    第9章 语句 1.标签语句 ①.标签语句由一个标识符后面跟着一个冒号再跟着一条语句组成 ②.标签语句的执行完全如同标签不存在一样,并仅执行冒号后的语句. ③.给语句添加一个标签允许控制从代码的另一部分 ...

随机推荐

  1. 安装运行mariadb时错误:gtid_slave_pos

    精简windows zip包后出现错误: Failed to load slave replication state from table mysql.gtid_slave_pos: 1932: T ...

  2. Struts2详细教程

    Struts2详细教程:http://www.yiibai.com/struts_2/

  3. jQuery总体架构

    第一章  总体架构 1.设计理念 jQuery的理念就是“写更少的代码,做更多的事”,而且做到代码的高度兼容性. 2.总体架构 大致可以分为三个部分:构造模块,底层支持模块和功能模块. 3.使用自调用 ...

  4. JQuery插件Validation的使用-遁地龙卷风

    第二版 (-1)写在前面 本文不是要详细说明Validation插件的使用,而是将满足开发需求的代码已最应该使用的方式写出来,并附有详细的注释 想要了解更多,去jquery的官网,有最新,最全面的,后 ...

  5. SharePoint 2013 JavaScript 对象判断用户权限

    场 景 近期有个场景,判断当前用户对项目有没有编辑权限,使用JavaScript完成,弄了好久才弄出来,分享一下,有需要的自行扩展吧,具体如下: 代 码 function getPermissions ...

  6. sqlite锁的机制

     reserved state 进入reserved state以后,sqlite可以修改数据库中的内容,不过把修改以后的内容写到pager的缓存里,大小由page cache指定. 进入这个状态以 ...

  7. 转 String,StringBuffer与StringBuilder的区别??

    String 字符串常量StringBuffer 字符串变量(线程安全)StringBuilder 字符串变量(非线程安全) 简要的说, String 类型和 StringBuffer 类型的主要性能 ...

  8. Android项目实战(十九):Android Studio 优秀插件: Parcelable Code Generator

    Android Studio 优秀插件系列: Android Studio 优秀插件(一):GsonFormat Android Studio 优秀插件(二): Parcelable Code Gen ...

  9. AFNetworking 3.0 源码解读 总结

    终于写完了 AFNetworking 的源码解读.这一过程耗时数天.当我回过头又重头到尾的读了一篇,又有所收获.不禁让我想起了当初上学时的种种情景.我们应该对知识进行反复的记忆和理解.下边是我总结的 ...

  10. iOS运用fabric记录crash日志过程

    先前运用友盟记录app闪退,发现有些闪退的记录无法明确定位到详细的位置,决定运用fabric进行闪退的记录:网上也有这方面的记录,有些细节的内容不明确,把今天碰到的坑整理记发不一下: 访问官网地址(进 ...