如果是使用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動畫了,接下來就讓我來給大家展示以下:
?1?HINSTANCE?handle?=?::AfxGetResourceHandle();//首先獲得資源句柄?
?2?HRSRC?hrsrc=?::FindResource(handle,MAKEINTRESOURCE(IDR_IMAGE2),"IMAGE");?
?3?DWORD?word?=?::SizeofResource(handle,hrsrc);?
?4?BYTE*?lpBy?=?(BYTE*)LoadResource(handle,hrsrc);//獲得圖象的首地址?
?5?BYTE*?pByte[20];?//用來儲存gif每幅圖象的地址?
?6?DWORD?nu[20];?//用來儲存每幅圖象的大小?
?7?int?num?=?0;?//用來計算有幾副圖象?
?8?DWORD?firstLocation?=?0;?//第一副圖象的位置,用來替換?
?9?for(DWORD?j=0;j<word;j++)?
10?{?
11??if(lpBy[j]==0x2c)?//圖象開頭?
12??{?
13???if(lpBy[j-1]==0x00)?//確認是否圖象開頭?
14???{?
15????if(num==0)?
16????{?
17?????firstLocation?=?j;?//得到第一副圖象位置?
18????}?
19????PGifImage?nowImage?=?(PGifImage)&lpBy[j+1];?
20????if(nowImage->Flag.a==0)?//a為0時指圖象不存在局部調色板?
21????{?
22?????DWORD?number?=?1+sizeof(GifImage);?
23?????while(lpBy[j+number]!=0)?
24?????{?
25??????number?=?number+(DWORD)lpBy[j+number]+1;?
26?????}?//算得圖象大小?
27?????number++;?
28?????//把最后一個0x00加上?
29?????pByte[num]?=?new?BYTE[number];?
30?????for(DWORD?n=0;n<number;n++)?
31?????{?
32??????*(BYTE*)(pByte[num]+n)?=?lpBy[j+n];?
33?????}?//將圖象儲存起來。?
34?????nu[num]?=?number;?
35?????j?=?j+number-1;?//跳過圖象?
36?????num++;?
37????}?
38????else?
39????{?
40?????//當a為1時需要加上局部調色板的大小,其他與a為0時一樣?
41?????int?number?=?1+sizeof(GifImage)+3*(int)floor(pow(2,nowImage->Flag.d));?
42?????while(lpBy[j+number]!=0)?
43?????{?
44??????number?=?number+(DWORD)lpBy[j+number]+1;?
45?????}?
46?????//算得圖象大小?
47?????number++;?
48?????//把最后一個0x00加上?
49?????pByte[num]?=?new?BYTE[number];?
50?????for(DWORD?n=0;n<number;n++)?
51?????{
52??????*(BYTE*)(pByte[num]+n)?=?lpBy[j+n];?
53?????}?
54?????//將圖象儲存起來。
55?????nu[num]?=?number;?j?=?j+number-1;?
56?????//跳過圖象?
57?????num++;?
58????}?
59???}?
60??}?
61?}?
62?int?working=?1;?
63?while(working)?
64?{?
65??for(int?m=0;m<num;m++)?
66??{?
67???CBrush?brush(RGB(255,255,255));?
68???pdc->FillRect(CRect(0,0,500,500),&brush);?
69???DWORD?DDD;?
70???VirtualProtect(lpBy,word,PAGE_READWRITE,&DDD);?
71???//修改頁面的保護屬性,以進行寫操作?
72???for(DWORD?n=0;n<nu[m];n++)?
73???{?
74????lpBy[firstLocation+n]?=?*(BYTE*)(pByte[m]+n);?
75???}?
76???VirtualProtect(lpBy,word,DDD,NULL);?
77???//因為IPicture必須把圖象存成流的形式才能工作,所以有下面一段函數?
78???CMemFile?file(lpBy,word);?
79???CArchive?ar(&file,CArchive::load|CArchive::bNoFlushOnDelete);?
80???CArchiveStream?arcstream(&ar);?
81???CComQIPtr<IPicture>?m_picture;?
82???HRESULT?hr?=?OleLoadPicture((LPSTREAM)&arcstream,0,false,?IID_IPicture,(void**)&m_picture);?
83???long?a,b;?
84???m_picture->get_Width(&a);?
85???m_picture->get_Height(&b);?
86???CSize?sz(a,b);?
87???pdc->HIMETRICtoDP(&sz);?
88???//時OLE格式的大小轉化為正常大小?
89???CRect?rect;?
90???m_picture->Render(*pdc,0,0,sz.cx,sz.cy,0,b,a,-b,&rect);?
91???Sleep(100);?
92???//停止一段時間。?
93??}
94?}
95?
96?
結尾語:本程序最好放在一個線程中進行工作,對于最后Sleep的毫秒數就讀者喜好進行修改,其實gif儲存格式中有一個圖象間隔的毫秒數,但是,筆者認為在此沒有必要,還是隨讀者的喜好較好。