如何显示在内存中的一个与设备无关的位图DIB

     显示位图,有许多的方法实现。本文主要介绍如何将内存中的与设备无关的位图,即一个内存块(可以是void*)显示在屏幕上。

通常,我们要显示一幅位图,一般是通过Windows API提供的位图贴图函数Bitblt来实现。在MFC中,CDC为我们封装了这个函数,他的原型为:BOOL BitBlt( int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, DWORD dwRop )。

其中各参数的意义为:

x和y是指定目标矩形左上角的逻辑x坐标和y坐标;

nWidth和nHeight是指定目标矩形和源位图的宽度和高度(逻辑单位);

pSrcDC是标识待拷贝位图的设备上下文,如果dwRop指定不包括源的光栅操作,则它必须为NULL;

xSrc和ySrc是指定源位图左上角的逻辑X坐标和Y坐标;

dwRop是指定要执行的光栅操作。光栅操作代码定义GDC如何合并输出操作中的颜色,包括当前画刷、可能的源位图和目标位图。

 

一般使用BitBlt的过程为:创建一个内存DC,载入位图并显示。假设位图的宽和高为width和height,显示在(0,0)位置。一般的实现有:

CDC* pDC = GetDC();

CDC hMenDC;
hMenDC.CreateCompatibleDC(pDC);

HBITMAP hBitmap;  //?,未知,后面算出
CBitmap Bitmap;
Bitmap.Attach(hBitmap);
CBitmap* pOldBitmap = NULL;
pOldBitmap = hMenDC.SelectObject(&Bitmap);

pDC->BitBlt(0,0, width, height, &hMenDC, 0, 0, SRCCOPY);
 
hMenDC.SelectObject(pOldBitmap);
Bitmap.Detach();
DeleteObject(hBitmap);
hMenDC.DeleteDC(); 

ReleaseDC(pDC);

 

现在的问题是,内存DC需要载入的是一个位图,但是我们的与设备无关的位图DIB却是一个内存块(void*),怎样才能将内存块与一个位图句柄连接起来呢。

 

在Windows API中,为我们提供了一个函数,可以将一个位图像素位的内存块转为一个位图句柄,这个函数为:

HBITMAP CreateDIBSection(
  HDC hdc,                 // handle to DC
  CONST BITMAPINFO *pbmi,  // bitmap data
  UINT iUsage,             // data type indicator
  VOID **ppvBits,          // bit values
  HANDLE hSection,         // handle to file mapping object
  DWORD dwOffset           // offset to bitmap bit values
);
其中,第2个参数是一个BITMAPINFO的数据结构,它的定义为:
typedef struct tagBITMAPINFO { 
  BITMAPINFOHEADER bmiHeader; 
  RGBQUAD          	bmiColors[1]; 
} BITMAPINFO, *PBITMAPINFO
其中,bmiHeader是一个类型为BITMAPINFOHEADER 的结构,bmiColors[1]是一个调色板的数据结构,由于现在的视频适配器都提供了24位的颜色显示模式,
所以一般这个参数不需要自己去处理,只有小于24位的时候才需要处理。所以为了实现DIB到HBITMAP的转换,就需要定义一个BITMAPINFOHEADER 结构。它的定义为:
typedef struct tagBITMAPINFOHEADER{
  DWORD  biSize; 
  LONG   biWidth; 
  LONG   biHeight; 
  WORD   biPlanes; 
  WORD   biBitCount; 
  DWORD  biCompression; 
  DWORD  biSizeImage; 
  LONG   biXPelsPerMeter; 
  LONG   biYPelsPerMeter; 
  DWORD  biClrUsed; 
  DWORD  biClrImportant; 
} BITMAPINFOHEADER, *PBITMAPINFOHEADER; 
 
因此,就需要实现结构里面的所有成员。如下所示:
LPBITMAPINFOHEADER lpbi = new BITMAPINFOHEADER;
 lpbi->biSize = sizeof(BITMAPINFOHEADER);
 lpbi->biBitCount = 24; //每个像素的位数:1,4,8,24
 lpbi->biClrImportant = 0;
 lpbi->biClrUsed = 0;
 lpbi->biCompression = BI_RGB;
 lpbi->biHeight = -m_Height;
 lpbi->biWidth = m_Width;
 lpbi->biPlanes = 1;
 lpbi->biSizeImage = m_Height*nPitch; //nPitch = ((DIB宽度×24)+31)/32×4(公式,是指每条扫描线含有多少像素)
 lpbi->biXPelsPerMeter = 0;
 lpbi->biYPelsPerMeter = 0;
接着就可以调用CreateDIBSection函数来创建位图句柄:
LPSTR lpTargetBits = NULL;
HBITMAP hBitmap = CreateDIBSection(pDC->m_hDC, (LPBITMAPINFO)lpbi, 
	DIB_RGB_COLORS, (VOID**)&lpTargetBits, NULL, 0);
由于第2个参数中的调色板未用,所以可以直接转换成BITMAPINFO结构,不会出问题。
最后,就可以拿位图来进行贴图操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值