win32双缓冲实现gif图片的动态显示

背景

并不是所有的gif图片显示都必须采用双缓冲,据本人实践的结果,透明背景的gif图片显示,需要双缓冲实现,而非透明背景的gif显示可能并不一定需要双缓冲,要了解如何不采用双缓冲实现gif图片的显示,可以参考我之前的文档,也可以在网上搜索一下就可以找到很多方法,从中选取适合自己的就好了。

问题来了,为什么透明背景的gif图片显示需要双缓冲呢?
这个问题涉及到透明背景图片的显示,透明背景的图片其实是显示在父窗口上的,如果在显示透明背景的图片时没有刷新父窗口,则会产生重影,但是刷新父窗口问题又来了,图片在刷新的时候会产生明显的闪烁。根据经验,遇到图片闪烁的问题,试着用双缓冲技术,问题可能会得到解决。

双缓冲原理

采用双缓冲技术,绘图时所有的操作都在缓存上进行,缓存可以看做是一块虚拟的屏幕,当在缓存上完成绘图时,再一次性复制到屏幕上,这样就看不到屏幕闪烁的现象了。
内存DC
内存DC是在内存中申请的一块内存,用于存放待绘制的图像,它只是一个单色的长宽各一个像素的显示面,必须与位图句柄建立联系才能使用。

HDC hMemDC = CreateCompatibleDC(hdc);

根据目标DC建立位图
根据MSDN,一个内存DC建立后是不能绘图的,必须给它选择一个与它高宽对应的位图,位图是多色的,这样就让内存DC成为多色的DC了。

HBITMAP hMemBmp = CreateCompatibleBitmap(hdc, wndWidth, wndHeight);

关联内存DC和位图句柄

HBITMAP hOldMem = (HBITMAP)SelectObject(hMemDC, hMemBmp);

完整代码

void _cdecl showimage(HWND hWnd)
{
     HDC hdc = GetDC(hWnd);

     HDC hMemDC = CreateCompatibleDC(hdc);
     HBITMAP hMemBmp = CreateCompatibleBitmap(hdc, 100, 100);
     HBITMAP hOldMem = (HBITMAP)SelectObject(hMemDC, hMemBmp);

     Image *image = new Image(L"timg.gif");
     if (image == NULL)
         return;

     UINT count = image->GetFrameDimensionsCount();
     GUID *pDimensionIDs = (GUID*)new GUID[count];
     image->GetFrameDimensionsList(pDimensionIDs, count);
     WCHAR strGuid[39];
     StringFromGUID2(pDimensionIDs[0], strGuid, 39);
     UINT frameCount = image->GetFrameCount(&pDimensionIDs[0]);
     delete[]pDimensionIDs;
     int size = image->GetPropertyItemSize(PropertyTagFrameDelay);
     static PropertyItem* pItem = (PropertyItem*)malloc(size);
     image->GetPropertyItem(PropertyTagFrameDelay, size, pItem);
     UINT fcount = 0;
     GUID Guid = FrameDimensionTime;

     Graphics graphics(hMemDC);
     while (true)
     {
         // Clear hMemDC with window background color
         RECT fillRc{0, 0, kInstallInterfaceWidth , kInstallInterfaceHeight };

         LOGBRUSH lb;
         lb.lbColor = RGB(251, 255, 242);
         lb.lbStyle = BS_SOLID;
         lb.lbHatch = 0;
         HBRUSH brush = CreateBrushIndirect(&lb);
         FillRect(hMemDC, &fillRc, brush);

         graphics.DrawImage(image, 0, 0, image->GetWidth(), image->GetHeight());

         //StretchBlt(hdc, 0, 0, kInstallInterfaceWidth, kInstallInterfaceHeight, hMemDC, 0, 0, kInstallInterfaceWidth, kInstallInterfaceHeight, SRCCOPY);
         BitBlt(hdc, 0, 0, kInstallInterfaceWidth, kInstallInterfaceHeight, hMemDC, 0, 0, SRCCOPY);

         image->SelectActiveFrame(&Guid, fcount++);
         if (fcount == frameCount)
             fcount = 0;
         //long lPause = ((long*)pItem->value)[fcount] * 10;
         long lPause = 100;
         Sleep(lPause);
     }
     SelectObject(hMemDC, hOldMem);
     ::DeleteObject(hMemBmp);
     ::DeleteObject(hMemDC);
     ReleaseDC(hWnd, hdc);
 }

版权声明:本文为zhuiyuanqingya原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。