分享

GDI位图和DIB位图

 启蒙彩魂 2011-02-27
  • 摘要:《Visual C++编程从基础到实践》第3章主要介绍的了MFC的概念及一些编程的基础。适合于Visual C++ 6.0的初学者和使用Visual C++从事开发的程序员;对于具有一定Visual C++编程经验的读者,也具有很好的参考价值。本文主要为GDI位图和DIB位图。
  • 标签:GDI  DIB  位图  编程  Visual  C++  Visual C++编程从基础到实践

5.3.4  GDI位图和DIB位图
GDI位图和DIB位图是两种不同的Windows位图,GDI位图是MFC的CBitmap类表示的,在CBitmap类的对象中,包含了一种和Windows的GDI模块有关的Windows数据结构BITMAP,该结果是与设备有关的,应用程序可以得到GDI位图数据的一个备份,但其中位图的安排完全依赖于显示设备。在同一台机器中,我们可以将GDI位图在不同的应用程序中任意地传送,但由于GDI位图对设备的依赖性,因此通过磁盘或调制解调器对它们进行传送没有太大的意义。
GDI位图是由保存位图数据的BITMAP结果定义的,BITMAP定义如下:

typedef struct tagBITMAP {  // bm 
LONG   bmType;  //位图类型
LONG   bmWidth; //以像素表示的位图宽度
LONG   bmHeight; //以像素表示的位图高度
LONG   bmWidthBytes; //每条扫描线的字节数
WORD   bmPlanes; //在位图中的颜色面数
WORD   bmBitsPixel; //描述像素颜色所需位数
LPVOID bmBits;  //指向构成图像数据的字符值数组的指针
} BITMAP;

DIB(Device-indepentent bitmap)位图是另外一种格式的位图,它完全解决了位图传送问题,任何运行Windows的机器都可以对DIB进行处理,它通常以后缀为BMP的文件形式保留在磁盘中,当BMP文件从磁盘文件中读出来以后,它通常被转成GDI位图,但必要的时候程序可直接利用DIB格式进行工作。
DIB位图区别于GDI位图的本质特性如下:
包含创建DIB位图设备上的颜色格式信息。
包含创建DIB位图设备上的分辨率信息。
包含创建DIB位图设备上的调色板信息。
包含用以将调色板的红、绿、蓝(RGB)颜色元素映像到DIB图像中的像素的位图数组。
包含数据压缩标志,它指示哪种数据压缩方案用于压缩磁盘文件。
1.使用GDI位图
使用GDI位图之前必须创建它,然后把它选进设备环境中,当使用完了以后,还得将它从设备环境中取出来,把它删掉,这是使用GDI位图的过程。
(1)生成位图
MFC提供了管理位图的CBitmap类,因此生成位图的第一步就是声明这个类的实例,如:
 
位图对象通常声明为一个主程序类(如视图类)的数据成员。一旦声明CBitmap对象,必须调用适当的CBitmap成员函数将对象初始化。下面介绍如何初始化CBitmap对象,一是调用LoadBitmap成员函数装入程序资源中的位图数据,一是调用成员函数Create CmpatibleBitmap生成空位图,运行程序时再画所要的图形。
将位图作为程序资源就可以利用交互式位图编辑程序来设计位图,如Visual C++图形编辑器和Windows 98 Paint等其他绘图程序,因此这种方法特别适用于生成相对复杂的或非几何图形,它们很难绘图函数生成。
为了用Visual C++图形编辑器设计位图,选择“Insert”菜单的“Resource”命令或按快捷键“Ctrl+R”,并在“Insert Resource”对话框中选择资源类型Bitmap,然后用Visual C++打开图形编辑器中的新位图窗口,之后可以设计所要的位图图形。
生成新位图时,Visual C++赋值默认标识符。方法是:双击位图窗口,在“Bitmap Properties”对话框中选择“General”标签,并在ID文本框中输入新的标识符。
无论在Visual C++图形编辑器中设计位图或是从位图文件引入,该位图都会加入程序资源。程序运行时,可以装入该位图并用它初始化位图对象。为此调用CBitmap成员函数LoadBitmap,例如:
 
LoadBitmap的参数是位图在图形编辑器中生成或从位图文件引入时赋予的标识符。
(2)初始化位图
既然可以在编辑器中设计位图,也可以在程序运行时初始化一个空位图并用MFC绘图函数在位图中画出所要的图案。步骤如下:
初始化空位图。
生成内存设备环境对象。
将位图选入内存设备环境对象。
在位图中对内存设备环境对象调用CDC绘图函数画出所要图形。
初始化空位图可调用CeateCompalibeBitmap函数,例如:
 
函数CeateCompalibeBitmap的第一个参数是设备环境对象的地址,生成的位图将与这个对象相联系的设备兼容,第二、三个参数分别是位图的宽度和高度,单位是图素。
调用CeateCompalibeBitmap时,Windows保留一块内存给位图。这个位图中存放的图素值最初是未定的,必须用绘图函数生成所要的图形。但在位图内画图前,要生成与位图相联系的设备环境对象,这就是内存设备环境对象。为了生成内存设备环境对象,先要声明CDC类的实例,再调用CDC的成员函数CreateCompatibleDC,例如:
 
函数CreateCompatibleDC的参数是设备环境对象的地址。接着调用CDC的成员函数SelectObject将位图对象选入内存设备环境对象,例如:
 
现在可以对内存设备环境对象调用CDC绘图函数在位图内画所要的图形了。
2.显示和处理位图
生成所需的位图之后,把位图显示在窗口上或其他设备上才是最终目的。MFC的CDC类提供了三个传送图形数据块的灵活而有效的函数PatBlt,BitBlt和StretchBlt。生成图形时可用这些函数,复制图形数据块和用简单或复杂的方法修改图形数据(如传递颜色或翻折图形)时也用这些函数。这些函数可用于将图形数据从同一设备显示表面的一个位置复制到另一个位置,也可用于在不同设备间或设备与位图间复制图形数据。
PatBlt可用通过CDC类的成员函数PatBlt画矩形区。在位操作环境中,当前刷通常指当前图案。尽管也可通过调用CDC::FillRect用当前图案填充区域,但PatBlt函数更加灵活,其原型如下:
 
前两个参数指定所画矩形区左上角的逻辑坐标,后两个参数按逻辑单位指定这个区的宽和高,最后一个参数是光栅操作码。光栅操作码提供了PatBlt的灵活性,它指定图案中的每个图素与目标地点的当前图素的组合方式,产生最后的目标图素颜色。
BitBlt函数可以把图形数据块从一个位置传送到另一位置,源位置和目标位置可以在同一设备(或位图)上,也可以在不同设备上,其原型如下:
 
前两个参数指定传送目标位置左上角的逻辑坐标,后两个参数指定传送的数据块逻辑尺寸。第五个参数pSrcDC是源设备环境对象的指针,第六、七个参数是源设备中位图的左上角逻辑坐标,最后一个参数是光栅操作码。
BitBlt将图形数据块从一个与第五个参数表示的环境对象相联系的设备复制到与调用函数的环境对象相联系的设备上。
StretchBlt是这三个位操作函数中最灵活的,它可用于完成BitBlt能完成的所有操作,还可以在传送时改变数据块的大小和将块翻转(水平、垂直或双向),其原型如下:
 
StretchBlt除了比BitBlt增加两个指明源位图宽和高的参数外,其他同BitBlt一样。这样StretchBlt可用于指定源块和目标块的大小,而BitBlt只能指定一个块的大小。如果目标大小小于源大小,则图形压缩,如果目标大小大于源大小则图形扩大。如果nWidth和nSrcWidth的符号不同,则目标图形是源图的水平镜像。同样,如果nHeight和nSrcHeight符号相反,则目标图形是源图的垂直镜像。
3.使用DIB位图
前面介绍的GDI位图都是与设备有关的,移植性很差。如果要将位图保存在文档中,以便其他机器能够对它进行读取,则必须使用与设备无关的格式。几乎所有的绘图应用程序的根据都是以DIB格式来处理BMP磁盘文件的。DIB格式可支持单色、16色及256色位图,也支持24位彩色位图。为了节省磁盘空间,DIB格式还可对16色和256色位图进行压缩。
4.BMP文件的组成
BMP图像文件结构可分为三部分:表头、调色板和图像数据。只有全彩色BMP图像文件内没有调色板数据,其余不超过256种颜色的图像文件都必须设定调色板信息,即使是单色BMP图像文件也不例外。
(1)BMP表头数据
Windows把BMP图像文件表头细分为两组数据结构:BITMAPFILEHEADER和BITMAPINFOHEADER,如果还需要调色板数据,则放在表头之后,两数据结构的内容如下:
 

 

 
(2)调色板数据
Windows将BMP图像文件的调色板数据结构命名为RGBQUAD,该结构描述组成一个颜色的红、绿、蓝相对强度值。其数据结构如下:
 
还有一个重要的数据结构BITMAPINFO,该结构由前面介绍的BITMAPINFOHEADER和RGBQUAD结构组成,它提供了WindowsDIB的大小和颜色的完整定义。因此也可这样说,DIB位图由两个不同的部分组成:描述位图大小和颜色的BITMAPINFO结构和定义位图像素的字节数组,BITMAPINFO的结构如下:
 
(3)不压缩图像数据
BMP图像文件对图像数据有三种处理方式:
不压缩数据,任何BMP图像文件都能以这种方式处理。
RLE4压缩法,这是专用于16色图像数据的压缩方法。
RLE8压缩法,只用于压缩处理256色图像数据。
不压缩图像数据是BMP图像文件的通用处理方式。虽然这种做法会使得BMP图像文件的大小大与其他有压缩处理的图像文件,但是少了压缩和解压缩的过程,也让BMP图像文件的读或存取文件的速度超过压缩处理的图像文件。既然没有了压缩处理的文件,只要了解图像数据的排列及存储方式,必能正确地处理未压缩数据的BMP图像文件。
BMP图像文件内的图像数据的排列顺序是以图像的左下角为起点,按照由左至右,由下至上的次序,将图像数据一点一点存入文件的。图像数据的存储方式是:单色图像是以一个字节记录8点;16色图像是一个字节记录两点,左边四个Bits存第一点,右边四个Bits存第二点;256色图像是一个字节记录一点;全彩色图像则是三个字节记录一点,而以RGB,RGB,RGB…的次序排列下来。除此之外,BMP文件规定文件内每行字节的个数必须是4的倍数,若未达到4的倍数,必须在每行的末端加上几个字节,以补足差额。
5.编写DIB类
由于MFC未提供DIB类,用户在使用DIB时将面临繁重的Windows API编程任务。幸运的是,Visual C++提供了一个较高层次的API,简化了DIB的使用。这些API函数实际上是由MFC的DibLook例程提供的,它们位于DibLook目录下的dibapi.cpp、myfile.cpp和dibapi.h文件中,主要包括:
ReadDIBFile:把DIB文件读入内存。
SaveDIB:把DIB保存到文件中。
CreateDIBPalette:从DIB中创建一个逻辑调色板。
PaintDIB:显示DIB。
DIBWidth:返回DIB的宽度。
DIBHeight:返回DIB的高度。
【实例5-2】  图片浏览器
光盘路径  /05/picture/
实例目的  创建一个图片的浏览器
本实例可以通过“打开”对话框打开一个指定的图片文件,并可以对图片进行放大/缩小观察,当图片大小超出窗口时还可以显示滚动条以方便查看。
1.创建工程
启动Microsoft Visual Studio 6.0,在IDE中依次选择“File?New”菜单命令,或直接按快捷键“Ctrl+N”,打开“New”对话框。
在“New”对话框中单击“Projects”选项卡,在列表框中选择“MFC AppWizard(.exe)”项,在“Project name”文本框中输入“picture”,其他使用默认值,单击“OK”按钮,弹出“MFC AppWizard-Step1”对话框。
在“MFC AppWizard-Step1”对话框中,选中“Single Document”单选框,其他使用默认值,然后单击“Next”按钮,在最后的“MFC AppWizard-Step6 of 6”对话框中选择视图基类为CScrollView,如图5-33所示。然后单击“Finish”按钮,在弹出的“New Project Information”对话框中单击“OK”按钮,就可以完成工程的创建。


图5-33  “MFC AppWizard-Step6 of 6”对话框

2.添加菜单项
在工作区中选择的Resource View标签,转到资源编辑窗口,双击“Menu? IDR_MAINFRAME”条目打开该菜单资源的编辑界面。
单击“查看”菜单,双击弹出的菜单项中选择最下面的空白菜单,在弹出的属性对话框中,选中“Pop-up”选项,在Caption文本框中输入:背景缩放。如图5-34所示。


图5-34  背景缩放属性框

设置完背景缩放菜单项后就自动弹出菜单项,用   的方法设置弹出的菜单项,各菜单选项的属性如表5-4所示,设置完菜单的界面如图5-35所示。

3.添加响应函数
在IDE主菜单项中依次选择“View”→“Class Wizard”,打开“MFC ClassWizard”对话框,选择“Member Maps”选项卡,在“Project”下拉列表框中选择“picture”,在“Class name”下拉列表框中选择“CPictureView”。
在“Object IDs”下拉列表框中选择要添加响应控件的ID。
在Message项中选中需要添加的消息,同时对话框的下部出现相应的提示。
单击“Add Function…”按钮,单击“OK”按钮就可以创建一个消息的处理函数,单击“Edit Code”按钮退出“ClassWizard”对话框,并自动定位在添加的函数上。
这里我们需要添加的响应函数如表5-5所示。添加完消息的“MFC ClassWizard”对话框界面如图5-36所示。

 

图5-36  “MFC ClassWizard”对话框

4.添加类成员
为视图类CPictureView添加函数和数据成员,如表5-6所示。

5.编写代码
在视图类CPictureView的头文件PictureView.h中,CPictureView的类定义前输入以下代码:
 
这段代码给出了缩放标志取值的宏定义。
在CPictureView类的构造函数CPictureView()中输入以下代码:
 
该段程序初始化数据,设置文件打开标志为false。
在CPictureView::GetBmp()函数中输入以下代码:
BOOL CPictureView::GetBmp(LPCTSTR lpszSourceName,CBitmap &bitmap)
 
程序的第一行使用Windows API函数LoadImage()载入文件路径字符串lpszSourceName所指的位图文件。语句“bitmap.Detach();”用于将原来载入的位图对象分离开来。语句“bitmap.Attach(hbmp);”使用成员函数Attach()将CBitmap类对象与载入的位图关联起来。
在这里,函数LoadImage()将lpszName指定的文件以位图格式载入,如果要载入以资源形式存储于程序中的位图,可以将lpszName改为资源ID。由于在GetBmp()函数的参数部分对bitmap是引用调用,因此,实际上这里将载入的位图对象与主调函数的实参联系起来。
在void CPictureView::OnFileOpen()函数中输入以下代码:
 
这段程序的开头定义了一个CFileDialog类对象dlg。CFileDialog类封装了Windows常用的文件对话框,提供了一种简单的与Windows标准相一致的文件打开和文件存盘对话框功能。
在CPictureView::OnDraw()函数中输入如下代码:
 


这段代码开头,用语句“bitmap.GetBitmap(&BMap);”取得位图的信息。中间的大段程序是对不同缩放条件进行判断,并取得缩放后的图形大小。然后用语句“SetScrollSizes(MM_TEXT, sizeTotal);”重置滚动窗口的边界,使得当窗口小于图像大小时显示滚动条。
在各个菜单项命令消息处理函数中输入的代码如下:
 
 
在CPictureView::OnEraseBkgnd()函数中输入以下代码:
 
6.编辑并运行程序
编辑并运行程序,如图5-37所示。单击“文件”菜单下的“打开”菜单项,打开要浏览的图片。


图5-37  打开图片

单击“查看”菜单下的“背景缩放”菜单项,可以对图片进行相应的改变,如图5-38所示,就是对图片进行缩小。


图5-38  缩小图片

【责任编辑:杨硕 TEL:(010)68476636-8001】

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多