如何在VC中显示动态的GIF

本文介绍如何在VC中实现GIF动态效果,通过使用IPicture接口和解析GIF图像存储格式,实现连续的GIF动画播放。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

下载本文示例源代码




如果是使用VB,也许这个话题是多余的,因为VB有一个图象控件可以非常容易地实现各种格式的图象显示功能,然而对于VC却没有一个象样的控件可以达到这种效果,怎么办?经过一段日子的研究,发现只需要实现两步工作,就可以在VC中实现如同VB中一样的gif动态效果。

本文将介绍的两部分是IPicture接口的使用和gif的储存格式,好象一听到储存格式,读者就不想再看下去了!其实不然,这里只须用到其最基本的一部分,请读者耐心地往下看。

一.IPicture接口

IPicture接口是一个com类,其成员函数可参见微软的MSDN,这里只需用到以下几个函数:

get_Width返回当前图像的宽度
get_Height返回当前图像的高度
Render在指定的位置、设备上下文上绘制指定的图像

IPicture的使用不需要CoCreateInstance函数,而只需要使用OleLoadPicture,鉴于此接口在许多文章杂志上均有介绍,这里略去(因为不是本文的重点)。

二.Gif储存格式

gif储存格式是一个非常复杂的内容,如果要讲透彻可以写很多篇文章,庆幸的是要实现本文的主题只需要知道其中的一个图象储存结构就可以了,这里定义该图象结构为gifImage:

typedef struct gifImage{
   WORD logX;
   WORD logY;
   WORD width;
   WORD height;
   struct flag{
          BYTE d:3;
          BYTE c:1;
          BYTE b:3;
      BYTE a:1;
   }Flag;
}GifImage,*PGifImage;
在该结构中,

logX为图象相对于逻辑屏幕左上角的x坐标,常为0;

logY为图象相对于逻辑屏幕左上角的y坐标,常为0;

width为图象的宽度;

height为图象的高度;

Flag为一个标志,a指是否存在局域性调色板,b为存储方式(与本主题无关),c为RGB值是否经过排序(无关),d为调色板的大小,为3*2^(d+1);

最后想提一下,因为每副图象都以0x2c开头,并且0x2c前面必为0,故在储存格式中要找到图象的起始位置,只需查找0x2c并且前面一个值为0(具体请看下面代码),其次,一副图象可能储存为多个数据块,每个数据快都是以数据长度为起始的,这一点很重要。即其图象储存为:

0x2c
图象开头
gifImage
图象头结构
BYTE Number
Number为一个跟gif压缩有关的数字,可以不理踩。
第一副图象的大小
 
......图象存储内容
第二副图象大小
 
...... 
...... 
...... 
0x00数据块结束

好,介绍完了主要的两大部分也该进入今天的主题了。由于使用IPicture接口可以非常轻松地显示gif的第一副图画,那么我们就是利用这一点,利用gif的图象格式,把第二,三。。。图画逐一拷贝到第一副图画的位置,再使用IPicture进行读取,便可以形成一副十分连续的gif动画了,接下来就让我来给大家展示以下:

HINSTANCE handle = ::AfxGetResourceHandle();//首先获得资源句柄 
HRSRC hrsrc= ::FindResource(handle,MAKEINTRESOURCE(IDR_IMAGE2),"IMAGE");
DWORD word = ::SizeofResource(handle,hrsrc);
BYTE* lpBy = (BYTE*)LoadResource(handle,hrsrc);//获得图象的首地址
BYTE* pByte[20];                //用来储存gif每幅图象的地址
DWORD nu[20];                   //用来储存每幅图象的大小
int num = 0;                    //用来计算有几副图象
DWORD firstLocation = 0;        //第一副图象的位置,用来替换
for(DWORD j=0;j<word;j++)
{
	if(lpBy[j]==0x2c)  //图象开头
	{
		if(lpBy[j-1]==0x00)             //确认是否图象开头
		{
			if(num==0)
			{
				firstLocation = j;     //得到第一副图象位置
			}
			PGifImage nowImage = (PGifImage)&lpBy[j+1];
			if(nowImage->Flag.a==0)        //a为0时指图象不存在局部调色板
                        {
                               DWORD number = 1+sizeof(GifImage);
                               while(lpBy[j+number]!=0)
                               {
                                   number = number+(DWORD)lpBy[j+number]+1;
                               }                        //算得图象大小
                               number++;                //把最后一个0x00加上
                               pByte[num] = new BYTE[number];
                               for(DWORD n=0;n<number;n++)
                               {
                                      *(BYTE*)(pByte[num]+n) = lpBy[j+n];
                               }                        //将图象储存起来。
                               nu[num] = number;
                               j = j+number-1;            //跳过图象
                               num++;
                        }
                        else
                        { //当a为1时需要加上局部调色板的大小,其他与a为0时一样
                               int number = 1+sizeof(GifImage)+3*(int)floor(pow(2,nowImage->Flag.d));
                               while(lpBy[j+number]!=0)
                               {
                                   number = number+(DWORD)lpBy[j+number]+1;
                               }                        //算得图象大小

                               number++;                //把最后一个0x00加上

                               pByte[num] = new BYTE[number];

                               for(DWORD n=0;n<number;n++)
                               {
                                      *(BYTE*)(pByte[num]+n) = lpBy[j+n];
                               }                        //将图象储存起来。
                               nu[num] = number;
                               j = j+number-1;            //跳过图象
                               num++;
                        }
                 }
          }
}

   int working= 1;
   while(working)
   {
          for(int m=0;m<num;m++)
          {
                 CBrush brush(RGB(255,255,255));
                 pdc->FillRect(CRect(0,0,500,500),&brush);
                 DWORD DDD;
                 VirtualProtect(lpBy,word,PAGE_READWRITE,&DDD);
		//修改页面的保护属性,以进行写操作
                 for(DWORD n=0;n<nu[m];n++)
                 {
                        lpBy[firstLocation+n] = *(BYTE*)(pByte[m]+n);
                 }
                 VirtualProtect(lpBy,word,DDD,NULL);

                 //因为IPicture必须把图象存成流的形式才能工作,所以有下面一段函数

                 CMemFile file(lpBy,word);
                 CArchive ar(&file,CArchive::load|CArchive::bNoFlushOnDelete);
                 CArchiveStream arcstream(&ar);
                 CComQIPtr<IPicture> m_picture;
                 HRESULT hr = OleLoadPicture((LPSTREAM)&arcstream,0,false,
		       IID_IPicture,(void**)&m_picture);
                 long a,b;
                 m_picture->get_Width(&a);
                 m_picture->get_Height(&b);
                 CSize sz(a,b);
                 pdc->HIMETRICtoDP(&sz);    //时OLE格式的大小转化为正常大小
                 CRect rect;
                 m_picture->Render(*pdc,0,0,sz.cx,sz.cy,0,b,a,-b,&rect);
                 Sleep(100);                  //停止一段时间。
          }
   }

原文:http://www.vckbase.com/document/viewdoc/?id=802
动态加载GIF动画 VC 实现 include "stdafx.h" #include "TransparentGif.h" #include "TransparentGifDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // CTransparentGifApp BEGIN_MESSAGE_MAP(CTransparentGifApp, CWinAppEx) ON_COMMAND(ID_HELP, &CWinApp::OnHelp) END_MESSAGE_MAP() // CTransparentGifApp 构造 CTransparentGifApp::CTransparentGifApp() { // TODO: 在此处添加构造代码, // 将所有重要的初始化放置在 InitInstance 中 } // 唯一的一个 CTransparentGifApp 对象 CTransparentGifApp theApp; // CTransparentGifApp 初始化 BOOL CTransparentGifApp::InitInstance() { // 如果一个运行在 Windows XP 上的应用程序清单指定要 // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, //则需要 InitCommonControlsEx()。否则,将无法创建窗口。 INITCOMMONCONTROLSEX InitCtrls; InitCtrls.dwSize = sizeof(InitCtrls); // 将它设置为包括所有要在应用程序中使用的 // 公共控件类。 InitCtrls.dwICC = ICC_WIN95_CLASSES; InitCommonControlsEx(&InitCtrls); CWinAppEx::InitInstance(); AfxEnableControlContainer(); // 标准初始化 // 如果未使用这些功能并希望减小 // 最终可执行文件的大小,则应移除下列 // 不需要的特定初始化例程 // 更改用于存储设置的注册表项 // TODO: 应适当修改该字符串, // 例如修改为公司或组织名 SetRegistryKey(_T("应用程序向导生成的本地应用程序")); CTransparentGifDlg dlg; m_pMainWnd = &dlg; INT_PTR nResponse = dlg.DoModal(); if (nResponse == IDOK) { // TODO: 在此放置处理何时用 // “确定”来关闭对话框的代码 } else if (nResponse == IDCANCEL) { // TODO: 在此放置处理何时用 // “取消”来关闭对话框的代码 } // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序, // 而不是启动应用程序的消息泵。 return FALSE; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值