GDI+ gif文件的显示和格式转换
怎么获取gif文件的每一帧,并且显示出来呢?
1.怎么用gid+显示gif文件
总体思路:用Image装载图像,用Graphic显示图像。
相关函数:
(1)Image::FromFile可以从文件中加载一个图像。
可以加载的文件类型有: BMP, GIF, JPEG, PNG, TIFF, and EMF
Image* image = Image::FromFile(_T("res//test.gif"));
(2)Image::GetFrameDimensionsCount 返回一个所谓的“维度”的个数,
每个维 度可能包含多个帧,gif文件就是包含1个维度,然后维度中可能包含
不定数目的帧。
UINT count = image->GetFrameDimensionsCount();
(3)Image::GetFrameDimensionsList 就是获得这些维度的GUID列表。
先分配count个GUID的数组。
GUID *pDimensionIDs=(GUID*)new GUID[count];
image->GetFrameDimensionsList(pDimensionIDs, count);
(4)Image::GetFrameCount获得指定的“维数”有多少帧。
UINT FrameNums=image->GetFrameCount(&pDimensionIDs[0]);
(5) 获得每帧之间的时间间隔。
PropertyTagFrameDelay是GDI+中预定义的一个GIG属性ID值,表示标
签帧数据的延迟时间。
先调用 Image::GetPropertyItemSize获得有多少个时间间隔属性item.
然后调用Image::GetPropertyItem填充获得的items.
UINT FrameDelayNums=image->GetPropertyItemSize
(PropertyTagFrameDelay);
PropertyItem * lpPropertyItem=new PropertyItem
[FrameDelayNums];
image->GetPropertyItem
(PropertyTagFrameDelay,FrameDelayNums,lpPropertyItem);
时间间隔就保存在PropertyItem的value成员中。
(6)最后,用一个while循环来循环显示每一帧。
Image::SetActiveFrame来设置显示那一帧。
总体的代码如下:
//装载gif文件 Image* image = Image::FromFile(_T("res//test.gif")); //获得有多少个维度,对于gif就一个维度 UINT count = image->GetFrameDimensionsCount(); GUID *pDimensionIDs=(GUID*)new GUID[count]; image->GetFrameDimensionsList(pDimensionIDs, count); TCHAR strGuid[39]; StringFromGUID2(pDimensionIDs[0], strGuid, 39); UINT frameCount=image->GetFrameCount(&pDimensionIDs[0]); delete []pDimensionIDs; //获得这个维度有多少个帧 UINT FrameNums=image->GetFrameCount(&pDimensionIDs[0]); //获得各帧之间的时间间隔 //先获得有多少个时间间隔,PropertyTagFrameDelay是GDI+中预定义的一个GIG属性ID值,表示标签帧数据的延迟时间 UINT FrameDelayNums=image->GetPropertyItemSize(PropertyTagFrameDelay); PropertyItem * lpPropertyItem=new PropertyItem[FrameDelayNums]; image->GetPropertyItem(PropertyTagFrameDelay,FrameDelayNums,lpPropertyItem); //Guid的值在显示GIF为FrameDimensionTime,显示TIF时为FrameDimensionPage int FrameCount=0; GUID Guid = FrameDimensionTime; image->SelectActiveFrame(&Guid,FrameCount); while(true) { Graphics gh(pDC->GetSafeHdc()); //显示当前帧 gh.DrawImage(image,0,0,image->GetWidth(),image->GetHeight()); //时间间隔 long lPause = ((long*)lpPropertyItem->value)[FrameCount]*10; Sleep(lPause); //设置当前需要显示的帧数 if ((FrameCount+1)==FrameNums) { //如果已经显示到最后一帧,那么重新开始显示 FrameCount=0; image->SelectActiveFrame(&Guid,0); } else { image->SelectActiveFrame(&Guid,++FrameCount); } }
2.怎么将gif中的某一帧提取出来,保存为其他的文件格式。
(1) Image::Save函数
Status Save(
const WCHAR *filename, const CLSID *clsidEncoder, const EncoderParameters *encoderParams );
其中第一个参数是表示要保存的文件名称,第二个参数是想采用的编码器,不同
的图片格式对应的编码器也不一样。第三个参数设为NULL即可。
(2)要得到参数2,必须调用函数:
Image::GetImageEncodersSize来获得编码器列表
Image::GetImageEncoders来获得对应的编码器相关信息(包括CLSID)
下面是相关的代码:
//获得指定格式的编码器的CLSID
int CTestGifImageDlg::GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes
ImageCodecInfo* pImageCodecInfo = NULL;
GetImageEncodersSize(&num, &size);
if(size == 0)
return -1; // Failure
pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if(pImageCodecInfo == NULL)
return -1; // Failure
GetImageEncoders(num, size, pImageCodecInfo);
for(UINT j = 0; j < num; ++j)
{
if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
{
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j; // Success
}
}
free(pImageCodecInfo);
return -1; // Failure
}
bool CTestGifImageDlg::DrawGifFrame(CDC * pDC)
{
//装载gif文件
Image* image = Image::FromFile(_T("res//test.gif"));
//获得有多少个维度,对于gif就一个维度
UINT count = image->GetFrameDimensionsCount();
GUID *pDimensionIDs=(GUID*)new GUID[count];
image->GetFrameDimensionsList(pDimensionIDs, count);
TCHAR strGuid[39];
StringFromGUID2(pDimensionIDs[0], strGuid, 39);
UINT frameCount=image->GetFrameCount(&pDimensionIDs[0]);
delete []pDimensionIDs;
//获得这个维度有多少个帧
UINT FrameNums=image->GetFrameCount(&pDimensionIDs[0]);
//将第一帧转换为png图片保存
GUID Guid = FrameDimensionTime;
image->SelectActiveFrame(&Guid,0);
//保存
CLSID encoderClsid;
if(GetEncoderClsid(_T("image/png"), &encoderClsid) >= 0)
{
image->Save(_T("pngfiles//test.png"),&encoderClsid,NULL);
}
}