首页
社区
课程
招聘
[讨论]用GDI+加载动态GIF中遇到的问题讨论。
发表于: 2011-8-18 01:24 10091

[讨论]用GDI+加载动态GIF中遇到的问题讨论。

2011-8-18 01:24
10091
最近在看GDIPLUS,看到了可以加载jpg,png,gif等格式的图片,顺手写了一个jpg,发现没问题,写了一个gif,发现只加载了gif的第一个帧,在codeproject+msdn上找到了一些资料:关于如何加载动态的gif图像。
首先写了一个加载GIF的函数如下:
void showimage(HDC hdc)
{
Image *image=new Image(L"123.gif");
	UINT count=0;
	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);
	PropertyItem* pItem=NULL;
	pItem=(PropertyItem*)malloc(size);
	image->GetPropertyItem(PropertyTagFrameDelay,size,pItem);
	UINT fcount=0;
	GUID Guid=FrameDimensionTime;
	while(true)
	{
		Graphics graphics(hdc);
		graphics.DrawImage(image,0,0,image->GetWidth(),image->GetHeight());
		image->SelectActiveFrame(&Guid,fcount++);
		if(fcount==frameCount)
			fcount=0;
		long lPause=((long*)pItem->value)[fcount]*10;
		Sleep(lPause);
	}
}

我把放到了WM_PAINT消息中,但是运行发现动态gif确实显示出来了,但是当程序窗口失去焦点进而发生重绘的时候发现图片就不会动了,最小最大化也是如此。具体原因也不是十分清楚,可能跟里面的那个死循环有关吧。
过了一会,想到了多线程来取代上述方法,只需要在主线程的WM_PAIT中创建一个线程,其他的显示工作都交给该线程去实现,代码如下:
void __cdecl showimage(LPVOID)
{
	HDC hdc=GetDC(g_hWnd);
	Image *image=new Image(L"123.gif");
	UINT count=0;
	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);
	PropertyItem* pItem=NULL;
	pItem=(PropertyItem*)malloc(size);
	image->GetPropertyItem(PropertyTagFrameDelay,size,pItem);
	UINT fcount=0;
	GUID Guid=FrameDimensionTime;
	while(true)
	{
		Graphics graphics(hdc);
		graphics.DrawImage(image,0,0,image->GetWidth(),image->GetHeight());
		image->SelectActiveFrame(&Guid,fcount++);
		if(fcount==frameCount)
			fcount=0;
		long lPause=((long*)pItem->value)[fcount]*10;
		Sleep(lPause);
	}
	ReleaseDC(g_hWnd,hdc);
}

WM_PAINT消息:
	case WM_PAINT:
			hdc = BeginPaint(hWnd, &ps);
			// TODO: Add any drawing code here...
			RECT rt;
			GetClientRect(hWnd, &rt);
			_beginthread(showimage,0,0);
			//showimage(hdc);
			EndPaint(hWnd, &ps);
			break;

运行发现此时上述的那个重绘时遇到的图片假死已经不复存在了,这个时候表明看起来没什么问题了,但是仔细看发现gif图片交换的频率好像快了不少(跟原来的123.gif进行了肉眼对比),显的跟原版图片还是有点差距的,这里又是啥原因呢,是因为Sleep的不准确所导致的吗?那有什么办法来解决此问题吗?还请各位大侠发表一下自己的看法。三克油。

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (10)
雪    币: 878
活跃值: (496)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
你线程还没执行玩就 EndPaint(hWnd, &ps);了
2011-8-18 09:02
0
雪    币: 359
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
窗口或者桌面的HDC应该不能长时间保留吧?如果屏幕分辨率或者色深改变之类的,是否会导致这类HDC失效?
你把循环绘图的代码换成定时器,不要使用长时间保留的窗口HDC,应该不会有这类问题。
2011-8-18 09:23
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
4
按照你说的,做了如下改变:
	hThread=(HANDLE)_beginthread(showimage,0,0);
			//showimage(hdc);
			WaitForSingleObject(hThread,INFINITE);
			EndPaint(hWnd, &ps);

运行发现跟上述的第一个问题一样,程序窗口失去焦点图片就不会动了,不知道我有没有理解你的意思啊你是这个意思吗
2011-8-18 09:37
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
5
把循环绘图改成定时器这样应该还是不太对的,因为gif是多帧图像,每个帧与每个帧之间的时间间隔是不一样的,用定时器无从下手吧
2011-8-18 09:47
0
雪    币: 150
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
一般做法。开一个定时器。然后取gif当前帧到下一帧的时间间隔,做为定时器的间隔(最小100ms)。(定时器只用一次)。每次定时器到了。就把活动帧设到下一帧,然后触发窗口重绘。
剩下的。你只需要在wm_paint里面,把gif的当前帧画出来就好了.
大概流程:
1.取帧间隔,开定时器。
2.定时器到。杀掉定时器,选中下一帧,再取帧间隔。
3.触发窗口重绘。
2011-8-18 09:58
0
雪    币: 359
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
gif最小时间间隔单位是10ms,在网页上显示至少花费10个时间间隔也就是100ms,你可以根据每一桢的时间间隔每次重设定时器,也可以固定10ms定时,每次溢出将间隔计数减少。
2011-8-18 12:47
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
8
非常感谢6楼的回答,按照你的回答已经成功解决了。同样也感谢7楼地思路。贴一下代码吧,免得论坛中的人以后遇到类似的问题可以少走弯路
//定义2个ID
#define TIMER_FIR 1
#define TIMER_SEC 2
//核心工作
case WM_CREATE:
		SetTimer(hWnd,TIMER_FIR,0,NULL);
		break;
	case WM_TIMER:
		{
			switch(wParam)
			{
	case TIMER_FIR:
		{
		hdc=GetDC(hWnd);
	image=new Image(L"123.gif");
 count=0;
  count=image->GetFrameDimensionsCount();
pDimensionIDs=(GUID*)new GUID[count];
  image->GetFrameDimensionsList(pDimensionIDs,count);
  StringFromGUID2(pDimensionIDs[0],strGuid,39);
frameCount=image->GetFrameCount(&pDimensionIDs[0]);
  delete []pDimensionIDs;
 size=image->GetPropertyItemSize(PropertyTagFrameDelay);
 //PropertyItem* pItem=NULL;
 // pItem=(PropertyItem*)malloc(size);
  pItem=(PropertyItem*)new PropertyItem[size];
  image->GetPropertyItem(PropertyTagFrameDelay,size,pItem);
fcount=0;
Guid=FrameDimensionTime;

Graphics  graphics(hdc);
   graphics.DrawImage(image,0,0);
    image->SelectActiveFrame(&Guid,fcount++);
    if(fcount==frameCount)
      fcount=0;
 lPause=((long*)pItem->value)[fcount]*10;
		//ReleaseDC(hWnd,hdc);
		KillTimer (hWnd, TIMER_FIR) ;
		SetTimer(hWnd,TIMER_SEC,lPause,NULL);
			  InvalidateRect (hWnd, NULL, FALSE) ;
		break;
		}
	case TIMER_SEC:
		{
		image->SelectActiveFrame(&Guid,fcount++);
		if(fcount==frameCount)
      fcount=0;
	 lPause=((long*)pItem->value)[fcount]*10;
	KillTimer(hWnd,TIMER_SEC);
	SetTimer(hWnd,TIMER_SEC,lPause,NULL);
	InvalidateRect (hWnd, NULL, FALSE) ;
		}
			}
		}

上传的附件:
2011-8-18 14:14
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
9
运行效果图示例:
上传的附件:
2011-8-21 20:14
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
10
跟大家分享一下GID+的详细学习资料。
上传的附件:
2011-12-7 15:55
0
雪    币: 412
活跃值: (30)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
11
这张图太有内涵了.
2011-12-8 12:28
0
游客
登录 | 注册 方可回帖
返回
//