使用GetDIBts/SetDIBits高速逐点处理 from http://blog.sina.com.cn/s/blog_552ad2090100e3eu.html

使用GetDIBts/SetDIBits高速逐点处理

 (2009-07-30 14:38:03)
标签: 

杂谈

 
 
 

之前逐点处理像素的时候都用GetPixel和SetPixel,对比了下坂本千寻系列里用的DIB,才知道那速度真不是一般的慢。前者可以看到扫描线,处理一张1024*800的图需要1~2s,但是后者处理相同大小的图几乎是即时的。

关于DIB(设备无关位图)和DDB(设备相关位图)有很多概念,经常弄得我云里雾里,实际上用起来,DDB就是和dc相关的位图,不同情况下用CreateBMP(),CreateCompatibleBMP(),LoadBMP(),LoadImage()等创建的就是DDB。DIB就是一片内存,里面存储着位图掐头去尾,只留下RGB(32位真彩,16位真彩),或者像素+色板(8位)的信息。

创建DIB也比较晕,坂本千寻系列里,读bmp,png,读像素点等函数都是自己写的。但是现在读写图片有很多好用的库,应该好好利用。所以,我的方法是,用CImage类读图->创建双缓存->读图到离屏dc->读内存bmp到DIB->GetDIBits->处理像素点->SetDIBits到屏幕dc。
//1.创建双缓存,创建DIB
//HDC hdc,memdc, HBITMAP memBmp为成员变量

hdc=::GetDC(m_hWnd);
memdc=CreateCompatibleDC(hdc);
memBmp=CreateCompatibleBitmap(hdc,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN));
SelectObject(memdc,memBmp);
//CImage *img为成员变量 #include <atlimage.h>
img=new CImage();
img->Load(_T("3.bmp"));
img->Draw(memdc,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN),0,0,img->GetWidth(),img->GetHeight());
//从HBITMAP获取BITMAP
CBitmap cbmp;
cbmp.Attach(memBmp);
cbmp.GetBitmap(&bm);
//创建DIB实际上就两步
//1. 在内存new出一片位图大小的空间,new BYTE,new char,GlobalAlloc都有人用
//2. 填写BITMAPINFO结构

DWORD size=bm.bmWidthBytes*bm.bmHeight; //每行像素位*图高
pBuf=new BYTE[size];
    
  
ZeroMemory(&binfo,sizeof(BITMAPINFO));
binfo.bmiHeader.biBitCount=bm.bmBitsPixel;      //每个像素多少位,也可直接写24(RGB)或者32(RGBA)
binfo.bmiHeader.biCompression=0;
binfo.bmiHeader.biHeight=bm.bmHeight;
binfo.bmiHeader.biPlanes=1;
binfo.bmiHeader.biSizeImage=0;
binfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
binfo.bmiHeader.biWidth=bm.bmWidth;
//下面就可以逐点处理了
//获取位图到内存DIB
GetDIBits(memdc,memBmp,0,binfo.bmiHeader.biHeight,pBuf,(BITMAPINFO*)&binfo,DIB_RGB_COLORS);
//逐点处理,这里是用来作淡出效果
//这里是一个颜色分量8位,而不是一个像素
for(int i=0;i<binfo.bmiHeader.biSizeImage;i++)
{
   pBuf[i]=pBuf[i]*level/256;
  
}

//全图处理完毕读出到屏幕dc显示
SetDIBits(hdc,memBmp,0,binfo.bmiHeader.biHeight,pBuf,(BITMAPINFO*)&binfo,DIB_RGB_COLORS);

原来DIB就是这么简单。

 

 

SetDIBits

 
 

函数功能

  该函数使用指定的DIB位图中发现的颜色数据来设置位图中的像素。

函数原型

  int SetDIBits(HDC hdc, HBITMAP hbmp, UINT uStartScan, UINT cScanLines, CONST VOID *lpvBits,CONST BITMAPINFO *lpbmi, UINT fuColorUse);

参数

  hdc:指向设备环境中的句柄。
 
  hbmp:指向位图的句柄。函数要使用指定DIB中的颜色数据对该位图进行更改。
 
  uStartScan:为参数lpvBits指向的数组中的、与设备无关的颜色数据指定起始扫描线
 
  cScanLines:为包含与设备无关的颜色数据的数组指定扫描线数目。
 
  lpvBits:指向DIB颜色数据的指针,这些数据存储在字节类型的数组中,位图值的格式取决于参数lpbmi指向的BITMAPINFO结构中的成员biBitCount。
 
  lpbmi:指向BITMAPINFO数据结构的指针,该结构包含有关DIB的信息。
 
  fuColorUse:指定是否提供了BITMAPINFO结构中的bmiColors成员,如果提供了,那么bmiColors是否包含了明确的RGB值或调色板索引。参数fuColorUse必须取下列值,各值的含义为:
 
  DIB_PAL_COLORS:颜色表由16bit的索引值数组组成。这些值可以对由hdc参数标识的设备环境中的逻辑调色板进行索引。
 
  DIB_RGB_COLORS:提供了颜色表,并且表中包含了原义的RGB值。

返回值

  如果函数成功,那么返回值就是复制的扫描线数;如果函数失败,那么返回值是0。
 
  Windows NT:若想获得更多错误信息,请调用GetLastError函数。
 

备注

  当位图的位要索引到系统调色板时,可获取最佳的位图绘制速度。
 
  应用程序可能通过调用GetSystemPaletteEntries函数来检索系统调色板颜色和索引。在检索到颜色和索引值之后,应用程序可以创建DIB,有关更多的信息,请参考系统调色板(System Paletle)。
 
  只有在参数fuColorUse设置为DIB_PAL_COLORS常量时才使用参数hdc标识的设备环境,否则会忽略hdc参数中的值。
 
  在应用程序调用该函数时,必须把由参数hbmp标识的位图选入到设备环境中。
 
  自底向上的DIB位图的起始点是该位图的左下角处,自顶向下的DIB位图的起源点在该位图的左上角处。
 
  ICM:颜色管理照样进行。如果指定的BITMAPINFO结构不是BITMAPV4HEADER或BITMAPV5HEADER,那么当前设备环境的颜色配置(profile)就用作源颜色配置。如果BITMAPINFO结构不是BITMAPV4HEADER或BITMAPV5HEADER,那么使用RGB颜色。如果指定的BITMAPINFO结构是BITMAPV4HEADER或BITMAPV5HEADER,那么与该位图有关的颜色配置(profile)被用作源颜色。
 
  速查:Windows NT:3.1及以上版本;Windows:95及以上版本;Windows CE:不支持;头文件:wingdi.h:库文件:gdi32.lib。

 

posted @ 2012-12-21 17:06  songtzu  阅读(1198)  评论(0编辑  收藏  举报