对于显示动态的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图片,你可以实现看看,有不懂的可以和我联系,下面有联系方式