主题:[原创]WMF 文件的数据格式以及将绘图保存为WMF图像的代码
WMF 文件的数据格式以及将绘图保存为WMF图像的代码
Wmf 是 Windows Metafile 的缩写,简称图元文件,它是微软公司定义的一种 Windows平台下的图形文件格式,是一个16位矢量图元文件格式,可以同时包含矢量信息和位图信息。图元文件与其它图形文件的最大区别在于:图元文件保存的是一系列用来重建图片的GDI函数(注:GDI函数是API 函数中的绘图函数)和参数,而其它图形文件则保存的是用以构成图像的像素数据。
WMF 图元文件是与设备无关的,它的图象完全由GDI 函数来完成,因此在建立图元文件时,不能实现即画即得,而是将GDI 调用记录在图元文件中,之后,在GDI 环境中重新执行,才可显示图象。正因为没有保存构成图像的像素数据,WMF 图元文件所占的磁盘空间比其它任何格式的图形文件都要小,形成文件的速度要远大于其它图形格式的文件。又正是因为显示图像时需要调用一系列的GDI 函数,所以WMF 图元文件的显示速度要比其它格式的图象文件慢。
WMF 文件又分为内存图元文件和磁盘图元文件。内存图元文件是仅在内存某一个区域进行操作并存放的,大多用于图象的绘制、拷贝或者进程间的剪切板图形共享;磁盘图元文件则主要用于将绘制图象保存到磁盘文件中,以便事后重看。
WMF 文件还可分为一般图元文件和“可确定位置”的图元文件。一般图元文件包含绘制直线、曲线和文本等记录,而可确定位置的图元文件还可以包含位图化图像。如果放大一般图元文件,那么得到的结果是放大的直线、曲线和其他输出,其抗锯齿能力很好。如果放大包含位图的图元文件,那么得到的结果是相对块状放大的位图,其抗锯齿能力要差一些。但一般图元文件也有不足之处,那就是:当将一个包含绘图命令的图元文件加载到一个应用程序时,可能会发现椭圆和文本不能正常地绘制出来,这是因为并不是所有程序都能够理解所有图元文件命令。
一、数据结构
WMF 文件的结构主要有两种,包括:
①WMF 文件头: 如果是可确定位置的图元文件,则还必须在WMF 文件头之前加上一个“位置头”。
②图元文件记录:其长度可变,记录中包含了建立图象时所需要的GDI 函数及参数。
下面以“可确定位置的图元文件”为例,介绍WMF文件的数据结构:
1.位置头,22字节:
-------------------------------------------------------------------------------
偏移量 名称 数据类型 说明
-------------------------------------------------------------------------------
0000 键 Long 总是=D7CDC69A,表示这是一个可确定位置的图元文件
0004 保留的 Integer 总是=0
(以下4个数据构成位图化图像的原始大小(逻辑单位)
0006 Left Integer 左上角X坐标
0008 Top Integer 左上角Y坐标
000A Right Integer 右下角X坐标
000C Bottom Integer 右下角Y坐标
000E 图像单元 Integer 每英寸逻辑单位数目
0010 保留的 Long 总是=0
0014 校验和 Integer
-------------------------------------------------------------------------------
说明:在资源管理器左侧的“详细信息”中显示的“尺寸”,宽度尺寸就是用Right值减去Left值、高度尺寸就是用Botton值减去Top值得到的。
2.WMF文件头,18字节:
---------------------------------------------------------------------
偏移量 名称 数据类型 说明
---------------------------------------------------------------------
0016 文件类型 Integer 0=内存图元文件, 1=磁盘图元文件
0018 文件头大小 Integer 总是=9
001A 版本 Integer 0300=支持设备无关位图,0100=不支持
001C 文件大小 Long 文件的总长度
0020 对象个数 Integer 文件中可以同时使用的对象数目
0022 最大记录大小 Integer 文件中最大记录的长度
0024 保留的 Long 未使用,总是=0
---------------------------------------------------------------------
说明:WMF 文件中的长度值是以“字数”为单位的(一个字=2字节),“文件头大小”、“文件大小”、“最大记录大小”,以及下面将要讲到的“文件记录大小”,都是如此。例如“文件头大小”总是=9,而 9×2=18字节。当然,这只是笔者的推测:这个推测还需验证。
3.文件记录:长度不定
紧接文件头的是文件记录,这是图元文件中最重要的组成部分,它表明当前图元文件所描述图像的基本构成信息,每个记录都是由记录头,定义函数的相应代码以及函数调用所需要的参数说明三部分组成,一个文件记录中只记录了一个GDI 函数及对应的参数。大多数情况下,记录中包含的参数恰好为需要传送到相应GDI 函数中的数据值,但对于某些包含结构的复杂类型定义,这些参数值也可能是非常复杂的数据编码。
文件记录是一个接一个地存放着的,它的结构如下:
----------------------------------------------------------------
偏移量 名称 数据类型 说明
----------------------------------------------------------------
0028 大小 Long 该记录的长度
002C 函数 Integer GDI函数编号
002E 参数表 欲传递给函数的参数值,整型和长整型参数
均为2字节,逻辑型或字节型参数为1字节
----------------------------------------------------------------
说明:
①记录的长度值,正如前面笔者所推测的,是指有多少个字。
②文件记录中的GDI 函数并不是它们的函数名称,而是对应的函数编号,根据这个编号来调用函数。
③有些API函数需用句柄,但句柄似乎没有保存。
④参数的排列规律为:如果是一般的参数,反序排列,如果是一个结构,顺序排列。
4.GDI函数在WMF文件中的16进制编号:
------------------------------------------------------------------
GDI函数名 编号 作用
------------------------------------------------------------------
savedc 001E 将设备场景状态保存到堆栈
Realizepalette 0035 将逻辑调色板映像为系统调色板
SETPALENTRIES 0037
AbortDoc 0052 取消一份文档的打印
CreatePalette 00F7 建立逻辑色彩调色板
SetBkMode 0102 指定填充方式
setmapmode 0103 设置设备场景的映射模式
SetROP2 0104 设置绘图模式
SetRelabs 0105
SetPolyFillMode 0106 设置多边形的填充模式
SetStretchBltMode 0107 指定函数的伸缩模式
SetTextCharacterExtra 0108 指定要在描绘的文本间插入的额外间距
RestoreDC 0127 从堆栈恢复一个原先保存的设备场景
INVERTREGION 012A
PAINTREGION 012B
SELECTCLIPREGION 012C
SelectObject 012D 选入图形对象到设备场景
SetTextAlign 012E 设置文本对齐方式
Resizepalette 0139 修改逻辑调色板大小
DIBCREATEPATTERNBRUSH 0142
DeleteObject 01F0 删除GDI对象
CreatePatternBrush 01F9 创建一个刷子
SetBkColor 0201 设置背景颜色
SetTextColor 0209 设置文本颜色
SetTextJustification 020A 指定一个文本行应占据的额外空间
SetWindowOrg 020B 设置设备场景窗口起点
SetWindowExt 020C 设置设备场景窗口范围
SetViewportOrg 020D 设置设备场景视口起点
SetViewportExt 020E 设置设备场景视口范围
OffsetWindowOrg 020F 平移设备场景窗口起点
OffsetViewportOrg 0211 平移设备场景视口区域
LineTo 0213 用当前画笔画一条线
MoveTo 0214 为设备场景指定一个新的当前画笔位置
OffsetClipRgn 0220 按指定量平移设备场景剪裁区
SetMapperFlags 0231 选择与目标设备的纵横比相符的光栅字体
SelectPalette 0234 选定调色板
CreatePenIndirect 02FA 根据指定的LOGPEN结构创建一个画笔
CreateFontIndirect 02FB 用指定的属性创建一种逻辑字体
CreateBrushIndirect 02FC 在LOGBRUSH结构的基础上创建一个刷子
Polygon 0324 描绘一个多边形
Polyline 0325 用当前画笔描绘一系列线段
ScaleWindowExt 0410 缩放设备场景窗口范围
ScaleViewportExt 0412 缩放设备场景视口范围
ExcludeClipRect 0415 从设备场景剪裁区中去掉一个矩形区
IntersectClipRect 0416 为指定设备定义一个新的剪裁区
Ellipse 0418 描绘一个椭圆
FloodFill 0419 用选定的刷子在设备场景中填充一个区域
Rectangle 041B 用选定的画笔描绘矩形
SetPixel 041F 在设备场景中画点(像素的RGB值)
AnimatePalette 0436 替换逻辑调色板中的项目
TextOut 0521 文本绘图
PolyPolygon 0538 用选定画笔描绘多边形
ExtFloodFill 0548 用选择的刷子填充一个区域
RoundRect 061C 画一个圆角矩形
PatBlt 061D 用一个图案填充指定的设备场景
Escape 0626 设备控制
CREATEREGION 06FF
Arc 0817 画一个圆弧
Pie 081A 画一个饼图
Chord 0830 画一个弦
BitBlt 0922 将位图从一个设备场景复制到另一个
DIBBITBLT 0940
ExtTextOut 0A32 文本描绘
StretchBlt 0B23 将位图从一个设备场景缩放到另一个
DIBSTRETCHBLT 0B41
SETDIBTODEV 0D33
StretchDIB 0F43 将位图部分数据复制到指定的设备场景
------------------------------------------------------------------
Wmf 是 Windows Metafile 的缩写,简称图元文件,它是微软公司定义的一种 Windows平台下的图形文件格式,是一个16位矢量图元文件格式,可以同时包含矢量信息和位图信息。图元文件与其它图形文件的最大区别在于:图元文件保存的是一系列用来重建图片的GDI函数(注:GDI函数是API 函数中的绘图函数)和参数,而其它图形文件则保存的是用以构成图像的像素数据。
WMF 图元文件是与设备无关的,它的图象完全由GDI 函数来完成,因此在建立图元文件时,不能实现即画即得,而是将GDI 调用记录在图元文件中,之后,在GDI 环境中重新执行,才可显示图象。正因为没有保存构成图像的像素数据,WMF 图元文件所占的磁盘空间比其它任何格式的图形文件都要小,形成文件的速度要远大于其它图形格式的文件。又正是因为显示图像时需要调用一系列的GDI 函数,所以WMF 图元文件的显示速度要比其它格式的图象文件慢。
WMF 文件又分为内存图元文件和磁盘图元文件。内存图元文件是仅在内存某一个区域进行操作并存放的,大多用于图象的绘制、拷贝或者进程间的剪切板图形共享;磁盘图元文件则主要用于将绘制图象保存到磁盘文件中,以便事后重看。
WMF 文件还可分为一般图元文件和“可确定位置”的图元文件。一般图元文件包含绘制直线、曲线和文本等记录,而可确定位置的图元文件还可以包含位图化图像。如果放大一般图元文件,那么得到的结果是放大的直线、曲线和其他输出,其抗锯齿能力很好。如果放大包含位图的图元文件,那么得到的结果是相对块状放大的位图,其抗锯齿能力要差一些。但一般图元文件也有不足之处,那就是:当将一个包含绘图命令的图元文件加载到一个应用程序时,可能会发现椭圆和文本不能正常地绘制出来,这是因为并不是所有程序都能够理解所有图元文件命令。
一、数据结构
WMF 文件的结构主要有两种,包括:
①WMF 文件头: 如果是可确定位置的图元文件,则还必须在WMF 文件头之前加上一个“位置头”。
②图元文件记录:其长度可变,记录中包含了建立图象时所需要的GDI 函数及参数。
下面以“可确定位置的图元文件”为例,介绍WMF文件的数据结构:
1.位置头,22字节:
-------------------------------------------------------------------------------
偏移量 名称 数据类型 说明
-------------------------------------------------------------------------------
0000 键 Long 总是=D7CDC69A,表示这是一个可确定位置的图元文件
0004 保留的 Integer 总是=0
(以下4个数据构成位图化图像的原始大小(逻辑单位)
0006 Left Integer 左上角X坐标
0008 Top Integer 左上角Y坐标
000A Right Integer 右下角X坐标
000C Bottom Integer 右下角Y坐标
000E 图像单元 Integer 每英寸逻辑单位数目
0010 保留的 Long 总是=0
0014 校验和 Integer
-------------------------------------------------------------------------------
说明:在资源管理器左侧的“详细信息”中显示的“尺寸”,宽度尺寸就是用Right值减去Left值、高度尺寸就是用Botton值减去Top值得到的。
2.WMF文件头,18字节:
---------------------------------------------------------------------
偏移量 名称 数据类型 说明
---------------------------------------------------------------------
0016 文件类型 Integer 0=内存图元文件, 1=磁盘图元文件
0018 文件头大小 Integer 总是=9
001A 版本 Integer 0300=支持设备无关位图,0100=不支持
001C 文件大小 Long 文件的总长度
0020 对象个数 Integer 文件中可以同时使用的对象数目
0022 最大记录大小 Integer 文件中最大记录的长度
0024 保留的 Long 未使用,总是=0
---------------------------------------------------------------------
说明:WMF 文件中的长度值是以“字数”为单位的(一个字=2字节),“文件头大小”、“文件大小”、“最大记录大小”,以及下面将要讲到的“文件记录大小”,都是如此。例如“文件头大小”总是=9,而 9×2=18字节。当然,这只是笔者的推测:这个推测还需验证。
3.文件记录:长度不定
紧接文件头的是文件记录,这是图元文件中最重要的组成部分,它表明当前图元文件所描述图像的基本构成信息,每个记录都是由记录头,定义函数的相应代码以及函数调用所需要的参数说明三部分组成,一个文件记录中只记录了一个GDI 函数及对应的参数。大多数情况下,记录中包含的参数恰好为需要传送到相应GDI 函数中的数据值,但对于某些包含结构的复杂类型定义,这些参数值也可能是非常复杂的数据编码。
文件记录是一个接一个地存放着的,它的结构如下:
----------------------------------------------------------------
偏移量 名称 数据类型 说明
----------------------------------------------------------------
0028 大小 Long 该记录的长度
002C 函数 Integer GDI函数编号
002E 参数表 欲传递给函数的参数值,整型和长整型参数
均为2字节,逻辑型或字节型参数为1字节
----------------------------------------------------------------
说明:
①记录的长度值,正如前面笔者所推测的,是指有多少个字。
②文件记录中的GDI 函数并不是它们的函数名称,而是对应的函数编号,根据这个编号来调用函数。
③有些API函数需用句柄,但句柄似乎没有保存。
④参数的排列规律为:如果是一般的参数,反序排列,如果是一个结构,顺序排列。
4.GDI函数在WMF文件中的16进制编号:
------------------------------------------------------------------
GDI函数名 编号 作用
------------------------------------------------------------------
savedc 001E 将设备场景状态保存到堆栈
Realizepalette 0035 将逻辑调色板映像为系统调色板
SETPALENTRIES 0037
AbortDoc 0052 取消一份文档的打印
CreatePalette 00F7 建立逻辑色彩调色板
SetBkMode 0102 指定填充方式
setmapmode 0103 设置设备场景的映射模式
SetROP2 0104 设置绘图模式
SetRelabs 0105
SetPolyFillMode 0106 设置多边形的填充模式
SetStretchBltMode 0107 指定函数的伸缩模式
SetTextCharacterExtra 0108 指定要在描绘的文本间插入的额外间距
RestoreDC 0127 从堆栈恢复一个原先保存的设备场景
INVERTREGION 012A
PAINTREGION 012B
SELECTCLIPREGION 012C
SelectObject 012D 选入图形对象到设备场景
SetTextAlign 012E 设置文本对齐方式
Resizepalette 0139 修改逻辑调色板大小
DIBCREATEPATTERNBRUSH 0142
DeleteObject 01F0 删除GDI对象
CreatePatternBrush 01F9 创建一个刷子
SetBkColor 0201 设置背景颜色
SetTextColor 0209 设置文本颜色
SetTextJustification 020A 指定一个文本行应占据的额外空间
SetWindowOrg 020B 设置设备场景窗口起点
SetWindowExt 020C 设置设备场景窗口范围
SetViewportOrg 020D 设置设备场景视口起点
SetViewportExt 020E 设置设备场景视口范围
OffsetWindowOrg 020F 平移设备场景窗口起点
OffsetViewportOrg 0211 平移设备场景视口区域
LineTo 0213 用当前画笔画一条线
MoveTo 0214 为设备场景指定一个新的当前画笔位置
OffsetClipRgn 0220 按指定量平移设备场景剪裁区
SetMapperFlags 0231 选择与目标设备的纵横比相符的光栅字体
SelectPalette 0234 选定调色板
CreatePenIndirect 02FA 根据指定的LOGPEN结构创建一个画笔
CreateFontIndirect 02FB 用指定的属性创建一种逻辑字体
CreateBrushIndirect 02FC 在LOGBRUSH结构的基础上创建一个刷子
Polygon 0324 描绘一个多边形
Polyline 0325 用当前画笔描绘一系列线段
ScaleWindowExt 0410 缩放设备场景窗口范围
ScaleViewportExt 0412 缩放设备场景视口范围
ExcludeClipRect 0415 从设备场景剪裁区中去掉一个矩形区
IntersectClipRect 0416 为指定设备定义一个新的剪裁区
Ellipse 0418 描绘一个椭圆
FloodFill 0419 用选定的刷子在设备场景中填充一个区域
Rectangle 041B 用选定的画笔描绘矩形
SetPixel 041F 在设备场景中画点(像素的RGB值)
AnimatePalette 0436 替换逻辑调色板中的项目
TextOut 0521 文本绘图
PolyPolygon 0538 用选定画笔描绘多边形
ExtFloodFill 0548 用选择的刷子填充一个区域
RoundRect 061C 画一个圆角矩形
PatBlt 061D 用一个图案填充指定的设备场景
Escape 0626 设备控制
CREATEREGION 06FF
Arc 0817 画一个圆弧
Pie 081A 画一个饼图
Chord 0830 画一个弦
BitBlt 0922 将位图从一个设备场景复制到另一个
DIBBITBLT 0940
ExtTextOut 0A32 文本描绘
StretchBlt 0B23 将位图从一个设备场景缩放到另一个
DIBSTRETCHBLT 0B41
SETDIBTODEV 0D33
StretchDIB 0F43 将位图部分数据复制到指定的设备场景
------------------------------------------------------------------