2411C++,gdi+的效率问题

原文

影响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;

}