当前位置:C++技术网 > 资讯 > GDI+实现GIF图片

GDI+实现GIF图片

更新时间:2015-12-17 21:58:09浏览次数:1+次

GIF文件是一种在互联网上广为流传的图形文件格式,尽管其文件对色彩的表示能力相当有限(不能显示色彩大于256图片),但它能够是实现简单的动画效果,文件体积小。
对于显示动态的GIF文件,程序开发人员只需要完成下面的工作:
1,按照时间顺序提取动态GIF文件的每一福静态图片
2,获取GIF文件中显示图片时使用的时间间隔

Image类的成员函数SelectActiveFrame讲多帧图片中的子帧图片按照"页"的顺序进行子帧图片的逐一读出,实现的过程有三步:

Image multi(L"Multiframe.gif");
///按页的顺序进行读取
GUID pageGuid=FrameDimensionPage;
multi.SelectActiveFrame(&pageGuid,0);
GIF文件对其自图片的读取顺序是按照时间顺序进行的,对应的GUID应该是由GDI+的"帧维常量",猎取的两一个常量FrameDimensionTime(帧维时间)。

代码实现:

新建对话框工程,并在对话框的头文件中定义初始化变量:

        Image *multi;
	int frames;
	int delaytime;
	int frameindex;
	CImageList m_ImageList1;
在对话框的OnInitDialog函数中写入代码:
CLSID encoderClsid;
	this->frameindex = 0;
	this->multi = Image::FromFile(L"FLAGANI.gif");

	/////为属性项分配空间
	int count = multi->GetPropertyCount();
	PROPID* propIDs = new PROPID[count];
	////得到图片的维度
	count = multi->GetFrameDimensionsCount();
	GUID* pDimensionIDs = new GUID[count];
	////得到子帧对象列表
	multi->GetFrameDimensionsList(pDimensionIDs, count);
	///获取总帧数
	this->frames = multi->GetFrameCount(&pDimensionIDs[0]);
	delete pDimensionIDs;
	////创建图像列表
	BOOL suc = m_ImageList1.Create(multi->GetWidth(), multi->GetHeight(),ILC_COLOR32,this->frames,1);
	if (!suc)
	{
		AfxMessageBox(L"图像列表控件创建出错!");
		return 0;
	}
	////设置列表空间的背景色为黑色
	m_ImageList1.SetBkColor(Color::Black);
	PropertyItem* propertyItem = NULL;
	///获取GIF图片两帧之间的时间延迟信息PropertyTagFrameDelay
	int size = multi->GetPropertyItemSize(PropertyTagFrameDelay);
	/////为PropertyTagFrameDelay分配空间
	propertyItem = (PropertyItem*)malloc(size);
	////获取PropertyTagFrameDelay项所有信息
	multi->GetPropertyItem(PropertyTagFrameDelay, size, propertyItem);
	/////获取延迟信息:propertyItem->value是一个指向void的指针
	this->delaytime = *(int*)propertyItem->value;
	delete propertyItem;
	/////获取BMP文件编码器
	GetEncoderClsid(L"image/bmp", &encoderClsid);
	/////FrameDimensionTime:按时间顺序访问GIF图片的子图片信息
	GUID pageGuid = FrameDimensionTime;
	////向图像列表追加位图
	for (int i = 0; i < this->frames; i++)
	{
		/////取出第i副图片
		multi->SelectActiveFrame(&pageGuid, i);
		///保存为临时图片
		multi->Save(L"tmp.bmp", &encoderClsid);
		////构造图像列表控件的图像
		Bitmap bmp(L"tmp.bmp");
		HBITMAP *tmpHBITMAP = new(HBITMAP);
		bmp.GetHBITMAP(Color::Black, tmpHBITMAP);
		CBitmap* tmpbmp = NULL;
		CBitmap* ImageListBmp = tmpbmp->FromHandle(*tmpHBITMAP);
		if (ImageListBmp == NULL)
		{
			AfxMessageBox(L"提取位图出错");
			delete tmpHBITMAP;
			return 0;
		}
		if (m_ImageList1.Add(ImageListBmp, RGB(0, 0, 0)) == -1)
		{
			AfxMessageBox(L"列表控件追加图像出错!");
			delete tmpHBITMAP;
			return 0;
		}
		delete tmpHBITMAP;
	}
	///根据GIF文件子图片之间的延迟信息建立计时器
	this->SetTimer(1, delaytime*10, NULL);
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}
WM_TIMER函数响应:
void CMultiGraphicsDlg::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	////GIF帧序号递增
	this->frameindex++;
	///让GIF文件在窗口中央播放
	int picWidth = this->multi->GetWidth();
	int picHeight = this->multi->GetHeight();
	CRect rect;
	this->GetClientRect(&rect);
	int centerx = (rect.Width() - picWidth) / 2;
	int centery = (rect.Height() - picHeight) / 2;
	CPoint p(centerx, centery);
	SIZE sz;
	sz.cx = picWidth;
	sz.cy = picHeight;
	CDC *pDC = this->GetDC();
	///图像列表控件根据当前索引号绘制
	m_ImageList1.DrawEx(pDC, this->frameindex, p, sz, RGB(0, 0, 0), RGB(0, 255, 255), ILD_TRANSPARENT);
	::ReleaseDC(this->m_hWnd, pDC->m_hDC);
	
	CDialogEx::OnTimer(nIDEvent);
}
在这里,我得提醒读者,因为这是GDI+工程,你需要引入必要的HDI+声明代码,而且这里用到了getencoderclsid函数,对于这个函数,我在《图片的编码与解码4》系列里面讲解了,如果你还是不懂的话,请你去看看。至于其他的调用解析GIF图片的函数,我在《GIF文件图形数据详解》里讲解了,你可以参考看看。

代码实现:

这是个GIF图片,你可以实现看看,有不懂的可以和我联系,下面有联系方式