DDB位图

位映射图像,简称“位图”,它使得计算机可以用1和0的形式保存复杂的图像。可分为“设备相关位图”(DDB)和“设备无关位图”(DIB)。另外还有“DIB扩展”。DDB是最简单也是功能最有限的位图,也是唯一一种MFC彻底封装的位图。

1.DDB和CBitmap类

在使用位图之前首先需要创建它,创建位图的一种途径是构造CBitmap对象并调用CBitmap::CreatCompatibleBitmap

  CBitmap bitmap;

  bitmap.CreateCompatibleBitmap(&dc,nWidth,nHeight);

  //nWidth,nHeight是像素单位的位图尺寸

  CreateCompatibleBitmap要求一个设备描述表指针,这是因为所生成的DDB的格式与输出设备的结构紧密相关。提供一个设备描述表指针,使Windows可以构造DDB,使他希望显示它的设备兼容。

  另一种创建位图的方法是调用CBitmap::CreateBitmap或CBitmap::CreateBitmapIndirect,并指定颜色位面数和每个颜色位面上每个像素的位个数,所有这两个都是设备相关值。目前CBitmap::CreateBitmap或CBitmap::CreateBitmapIndirect唯一的实际用途是创建单色位图。

  用创建的DDB最初包含随机数据,如果想使用DDB,如在屏幕中显示他们,需要首先在其中绘制些内容。要用GDI函数绘制位图,首先创建一个特殊类型的设备描述表,称为“内存设备描述表”,然后将位图选入内存DC。实际上,选入内存设备描述表的位图会成为设备描述表的显示面,正如相应的屏幕DC是屏幕自身一样。如下,程序创建了一个未初始化的DDB,它具有100×100像素,然后再创建一个内存设备描述表,并将位图选入其中,并将所有位图中的像素初始化为蓝色:

  CClientDC dcScreen(this);

  CBitmap bitmap;

  bitmap.CreateCompatibleBitmap(&dcScreen,100,100);

  CDC dcMem;

  dcMem.CreateCompatibleDC(&dcScreen);

  CBrush brush(RGB(0,0,255));

  CBitmap* pOldBitmap=dcMem.SelectObject(&bitmap);

  dcMem.FillRect(CRect(0,0,100,100),&brush);

  dcMem.SelectObject(pOldBitmap);

  CDC::CreateCompatibleDC创建一个与指定的设备描述表兼容的内存设备描述表,其中传递的地址是设备描述表的地址,通常指的是屏幕设备描述表。在位图选入内存sbmsb后,就可以用给屏幕设备描述表绘制输出时所用的同样的CDC成员函数来对内存设备描述表(也是给位图)绘制图像了。

  但是给内存设备描述表绘制的图像不会显示出来,要显示他们就需要将其从内存设备描述表复制到设备描述表。

2.按位将位图传送到屏幕

  怎样把位图绘制在屏幕上呢?不能把位图选入非内存DC中,如果这样做,SelectObject将返回NULL。但是可以使用CDC::BitBlt和CDC::StretchBlt将像素从内存设备描述表“位块传送”到屏幕设备描述表上。如果dcMem是一个内存设备描述表,包含有100×100个像素的图像,而且dcScreen时屏幕设备描述表,则下列语句可以将图像复制给屏幕使其在屏幕上显示。

  dcScreen.BitBlt(0,0,100,100,&dcMem,0,0,SRCCOPY);

  前两个参数制定了图像的左上角在目标(屏幕)设备描述表中的坐标接下来的两个参数制定了所传送像素块的宽度和高度,第五个参数是指向源(内存)设备描述表的指针,第6、7个参数制定了在源DC中像素块左上角的坐标,第8个即最后一个参数指定了在传送中所用的光栅操作类型。SRCCOPY将像素从内存设备描述表复制到屏幕设备描述表而不进行任何修改。

  下列语句将一个100×100的图像从内存设备描述表位块传送到屏幕设备描述表,并将该图像伸展来是和一个50×200的矩形:

  dcScreen.StretchBlt(0,0,50,200,&dcMem,0,0,100,100,SRCCOPY);

  在默认状态下,当目标DC中的图像宽度和高度小于源DC中的宽度和高度时,在结果图像中相应的行列像素就会被简单地删除。

3.位图资源

  如果仅仅是显示一个预定义的位图(该位图是用Visual C++资源编辑器或其他画图程序或图像编辑器生成的BMP文件),那么就可以用类似于下面给出的语句将位图资源添加到应用程序的RC文件中:

  IDB_MYLOGO BITMAP Logo.bmp

然后再加载它,如下:

  CBitmap bitmap;

  bitmap.LoadBitmap(IDB_MYLOGO);

还可以赋予位图资源一个字符串ID并按以下方式加载:

  bitmap.LoadBitmap(_T("Mylogo"));

  在加载了位图资源之后,就可以用显示其他位图的方式显示它了,将其选入内存设备描述表并位块传送到屏幕设备描述表。

4.DIB和DIB分区

  设备相关位图存在额问题是——它们是设备相关的。由于像素颜色数据是以设备相关的格式保存的,所以除非位图是单色的,否则根本操纵不了位图颜色。也就是说将DDB写入某个PC的磁盘,然后在另一个PC上将其读出,很容易看到结果颜色不再相同了,可移植性差。这就是Windows 3.0引入设备无关位图(DIB)的原因。DDB只在一个窗口的生命周期之内才有意义!

  在调用::CreateBitmap(与API等价的是CBitmap::CreateBitmap)创建一个位图时,会得到一个HBITMAP句柄。而调用::CreateDIBitmap创建位图时,也会得到一个HBITMAP句柄,不同之处在于内部。传递给::CreateBitmap的像素数据是以设备相关格式保存的,而传递给::CreateDIBitmap的数据是以DIB格式保存的。而且,DIB格式还包含其他颜色信息,可使不同的设备驱动程序输出一致的颜色。Windows BMP文件是以DIB格式存储的,所以很容易用::CreateDIBitmap编写一个函数将BMP文件的内容转换为GDI位图对象(也就是DDB)。

  但是目前MFC中没有分装DIB。要在MFC应用程序中使用DIB,必须求助于API或者编写自己的类来封装相关的API函数。

5.::LoadImage

  ::LoadImage对于DIB扩展就相当于::LoadBitmap和CDC::LoadBitmap,其可以从文件路径中加载位图资源。但还不仅是这些。如果成功创建了DIB扩展,由::LoadImage返回的值就是有效的HBITMAP,否则返回NULL,很有可能因为文件不包含DIB。::GetDIBColorTable只有在DIB扩展被选入设备之后才能使用,因此如果需要获取位图的颜色表,则需要使用::LoadImage加载DIB,然后将::LoadImage得到的HBITMAP使用attach到一个CBitmap,并将这个CBitmap选入内存DC。

  书中说明了用::LoadImage从BMP文件中创建一个DIB扩展并将其附加给CBitmap对象的方法。

6.详解DIB

6.1DIB文件格式

  可以将DIB认为就是一种文件格式,DIB文件的扩展名是BMP,在极个别的情况下也可以是DIB。

  程序可以把DIB文件除去开始的14个字节外,整个载入到一块连续的内存去榆中,这有时被称为“紧凑DIB格式的位图”。WIndows下的应用程序可以用这种格式创建画刷或者通过Windows剪切板来交换图像。程序还拥有对该DIB内容的完全控制,可以对此DIB进行任意修改。

  程序也可以在内存中创建自己的DIB,然后把他们存到文件中。这些DIB中的图像可以工GDI函数绘制。程序也可以直接对像素操作,在此过程中可以使用其他基于内存的DIB。

6.2

posted @ 2023-07-05 23:36  沙漠之狗  阅读(24)  评论(0)    收藏  举报