轉自:http://hi.baidu.com/shallow_sleep/blog/item/2fde85123c04f256f819b8b5.html
之前逐點處理像素的時候都用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就是這麼簡單。