原文
影响GDI+效率的主要有: 1,DrawImage,比起传输位实在差的不是一点点,解决的方法就是用传输位替换DrawImage. 2,PixelFormat,原来没想到这个也会影响效率,但事实就是这样. 位图在新出来的时候是和图片本身的格式有关的,但在最终画到DC上的可不一定是这个格式,具体的格式请查阅MSDN:ImagePixelFormatConstants.
如果格式不对,DrawImage时,也会转换图片格式,这个也会浪费一定的时间.
一个做法就是位图在新出来后用复制到一个新的位图,这时可以转换成指定的PixelFormat的:)统一成一种格式,特别是大图时,效果比较明显.
3,尽量用缓存位图替代直接使用位图也能优化一些效率. 4,每次都全部重画是一种浪费,能不重画的就不重画,刷新区域也是优化的一个有效方式. 5,构造对象比较费时,比如双缓冲的内存位图和图形最好设成成员变量,而不是在OnPaint中每次新建. 6,减小图片大小:) …
GDI和GDI+
GDI的效率更高,而GDI+无疑更加易用,鱼与熊掌不可兼得. 我现在的做法是用GDI+画到内存位图上,最后用GDI的BitBlt画到DC上. 1,InitDialog中用CreateDib创建出hBmpSection,并得到他的bmpData. 2,程序的某个地方把你的东西画到gdi+的位图上 3,调用FlushToDib,把你的位图写到第一步的bmpData中 4,OnPaint中间,hBmpSection用传输位画到dc上.
/*@ Function : CreateDib
@ brief : 创建内存位图
@ parameter : w
@ parameter : h
@ parameter : [out] hBmpSection OnPaint中会把这个位图直接往dc上贴
@ parameter : [out] bmpData 位图的实际数据,gdiplus的会把东西都话到上面
@ return :
@ remark :
@*/
BOOL CreateDib(int w, int h, OUT HBITMAP& hBmpSection, OUT BYTE** bmpData)
{
BITMAPINFO info = {0};
info.bmiHeader.biSize = sizeof(info.bmiHeader);
info.bmiHeader.biWidth = w;
info.bmiHeader.biHeight = -h;
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biBitCount = 32;
info.bmiHeader.biCompression = BI_RGB;
info.bmiHeader.biSizeImage = w * h * 32 / 8;
HDC hdc = ::GetDC(NULL);
hBmpSection = ::CreateDIBSection(hdc, &info, DIB_RGB_COLORS, (void**)bmpData, NULL, 0);
::ReleaseDC(NULL, hdc);
return hBmpSection != NULL;
}
/*
@ Function : FlushToDib
@ brief : 将Gdiplus的Bitamp转存到gdi的内存位图上
@ parameter : [in] pMemBitmap
@ parameter : [in, out] bmpData 就是上面的函数创建处理的内存位图的数据区
@ return :
@ remark :
@*/
void FlushToDib(IN Bitmap* pMemBitmap, IN OUT BYTE** bmpData)
{
BitmapData data;
data.Height = pMemBitmap->GetHeight();
data.PixelFormat = pMemBitmap->GetPixelFormat();
data.Scan0 = *bmpData;
data.Stride = (pMemBitmap->GetWidth() * 32 / 8);
data.Width = pMemBitmap->GetHeight();
Rect rct(0, 0, pMemBitmap->GetWidth(), pMemBitmap->GetHeight());
pMemBitmap->LockBits(&rct, ImageLockModeRead | ImageLockModeUserInputBuf, pMemBitmap->GetPixelFormat(), &data);
pMemBitmap->UnlockBits(&data);
}
// m_hBmpSection是InitDialog时用CreateDib创建出来的
LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
CPaintDC dc(m_hWnd);
HDC hdcMen = ::CreateCompatibleDC(dc.m_hDC);
HBITMAP hOldBmp = (HBITMAP)::SelectObject(hdcMen, m_hBmpSection);
// 宽度和高度自己取下
::BitBlt(dc.m_hDC, 0, 0, m_width, m_height, hdcMen, 0, 0, SRCCOPY);
::SelectObject(hdcMen, hOldBmp);
::DeleteDC(hdcMen);
return TRUE;
}
/*
@ Function : CreateDib
@ brief : 创建内存位图
@ parameter : w
@ parameter : h
@ parameter : [out] hBmpSection OnPaint中会把这个位图直接往dc上贴
@ parameter : [out] bmpData 位图的实际数据,gdiplus的会把东西都话到上面
@ return :
@ remark :
@*/
BOOL CreateDib(int w, int h, OUT HBITMAP& hBmpSection, OUT BYTE** bmpData)
{
BITMAPINFO info = {0};
info.bmiHeader.biSize = sizeof(info.bmiHeader);
info.bmiHeader.biWidth = w;
info.bmiHeader.biHeight = -h;
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biBitCount = 32;
info.bmiHeader.biCompression = BI_RGB;
info.bmiHeader.biSizeImage = w * h * 32 / 8;
HDC hdc = ::GetDC(NULL);
hBmpSection = ::CreateDIBSection(hdc, &info, DIB_RGB_COLORS, (void**)bmpData, NULL, 0);
::ReleaseDC(NULL, hdc);
return hBmpSection != NULL;
}
/*
@ Function : FlushToDib
@ brief : 将Gdiplus的Bitamp转存到gdi的内存位图上
@ parameter : [in] pMemBitmap
@ parameter : [in, out] bmpData 就是上面的函数创建处理的内存位图的数据区
@ return :
@ remark :
@*/
void FlushToDib(IN Bitmap* pMemBitmap, IN OUT BYTE** bmpData)
{
BitmapData data;
data.Height = pMemBitmap->GetHeight();
data.PixelFormat = pMemBitmap->GetPixelFormat();
data.Scan0 = *bmpData;
data.Stride = (pMemBitmap->GetWidth() * 32 / 8);
data.Width = pMemBitmap->GetHeight();
Rect rct(0, 0, pMemBitmap->GetWidth(), pMemBitmap->GetHeight());
pMemBitmap->LockBits(&rct, ImageLockModeRead | ImageLockModeUserInputBuf, pMemBitmap->GetPixelFormat(), &data);
pMemBitmap->UnlockBits(&data);
}
// m_hBmpSection是InitDialog时用CreateDib创建出来的
LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
CPaintDC dc(m_hWnd);
HDC hdcMen = ::CreateCompatibleDC(dc.m_hDC);
HBITMAP hOldBmp = (HBITMAP)::SelectObject(hdcMen, m_hBmpSection);
// 宽度和高度自己取下
::BitBlt(dc.m_hDC, 0, 0, m_width, m_height, hdcMen, 0, 0, SRCCOPY);
::SelectObject(hdcMen, hOldBmp);
::DeleteDC(hdcMen);
return TRUE;
}