近期有个需求,要做一个拍照后把图片四个一组显示出来,并且可以删除可以预览,顺便回顾了一下windows的GDI(WIN32)。
一开始使用的方法是
void DrawImage(LPCTSTR szFileName,HDC hdc,RECT rc)
{
IImagingFactory *pImgFactory = NULL;
IImage *pImage = NULL;
FillRect(hdc,&rc,(HBRUSH)GetStockObject(WHITE_BRUSH));
// Normally you would only call CoInitialize/CoUninitialize
// once per thread. This sample calls CoInitialize in this
// draw function simply to illustrate that you must call
// CoInitialize before calling CoCreateInstance.
// Create the imaging factory.
if (SUCCEEDED(CoCreateInstance (CLSID_ImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_IImagingFactory,
(void **)&pImgFactory)))
{
// Load the image from the JPG file.
if (SUCCEEDED(pImgFactory->CreateImageFromFile(
szFileName,
&pImage)))
{
// Draw the image.
pImage->Draw(hdc, &rc, NULL);
pImage->Release();
}
pImgFactory->Release();
}
}
采用这个办法,在WINPAINT的消息中直接把取得的窗体DC穿进去,然后传进去文件名以及画图位置就可以,奈何这种方法要把一张图先解码出来,然后再缩小,再画到指定区域,导致画一张图非常慢,大概在300-400毫秒之间,一张图片还好说,如果是四张图片那就需要1600毫秒,严重影响了程序的流畅度。之后采用了一个分步骤完成的方法,就是图片保存的时候就把图片LOAD到pImage中,之后再在WINPAINT消息中画出来。可是发现速度完全没有一点提高。看来CreateImageFromFile这个函数只是进行了一些准备工作,而解码,画图都是在DRAW函数中完成的。
之后在网上看到打开jpg的另一种方法,用CIMAGE类,结果发现CIMAGE类在CE下进行了限制,只能读入资源内的图片。所以这个解决方案也被否决了。
其实一开始我就想到了双缓冲的办法,无奈没有在WINDOWS的GDI下操作过,也不知道这种方法到底能不能解决我的问题,因为双缓冲算法是解决闪烁的,可是我这个是显示慢。后来,我把双缓冲算法的一部分拿出来,也就是在用户保存的时候,我把这张图通过兼容DC先画一份保存在内存当中,接下来再在显示的时候,把内存中的这几张图拷贝到屏幕上来,最终解决了这个问题。代码:
用户保存图片时,进行如下操作:
BOOL CapturePreviewDlg::LoadJpegImage(LPCTSTR szFileName,int nPicNum)
{
IImagingFactory *pImgFactory=NULL;
IImage *pImage=NULL;
// Normally you would only call CoInitialize/CoUninitialize
// once per thread. This sample calls CoInitialize in this
// draw function simply to illustrate that you must call
// CoInitialize before calling CoCreateInstance.
// Create the imaging factory.
if (SUCCEEDED(CoCreateInstance (CLSID_ImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_IImagingFactory,
(void **)&pImgFactory)))
{
// Load the image from the JPG file.
if (SUCCEEDED(pImgFactory->CreateImageFromFile(
szFileName,
&pImage)))
{
HDC dc=CreateCompatibleDC(NULL);
DeleteObject(g_Bitmap[nPicNum]);
g_Bitmap[nPicNum]=CreateBitmap(70,70,1,16,NULL);
HBITMAP h_oldBit=(HBITMAP)SelectObject(dc,g_Bitmap[nPicNum]);
RECT temprect={0,0,70,70};
pImage->Draw(dc,&temprect,NULL);
SelectObject(dc,h_oldBit);
DeleteDC(dc);
pImage->Release();
return TRUE;
}
else
pImgFactory->Release();
return FALSE;
}
return FALSE;
}
用户需要查看图片列表时,进行如下操作
BOOL CaptureImageListDlg::DrawJpegImage(int nPicNum,HDC hdc,RECT rc)
{
if (g_Bitmap[nPicNum]!=NULL)
{
HDC dc=CreateCompatibleDC(NULL);
HBITMAP h_oldbitmap=(HBITMAP)SelectObject(dc,g_Bitmap[nPicNum]);
BitBlt(hdc,rc.left,rc.top,70,70,dc,0,0,SRCCOPY);
SelectObject(dc,h_oldbitmap);
DeleteDC(dc);
return TRUE;
}
else
{
return FALSE;
}
}