溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

C#實(shí)現(xiàn)合并多個(gè)圖像文件為一個(gè)動(dòng)態(tài)GIF

發(fā)布時(shí)間:2020-06-23 21:06:36 來(lái)源:網(wǎng)絡(luò) 閱讀:2547 作者:cnn237111 欄目:編程語(yǔ)言

GIF簡(jiǎn)介

要實(shí)現(xiàn)合并為GIF文件,首先要對(duì)GIF文件格式有所了解。GIF由 CompuServe在1987年提出,官方文檔gif89a標(biāo)準(zhǔn)將GIF分成很多區(qū)塊,并給出的GIF語(yǔ)法格式如下:

<GIF Data Stream> ::=     Header <Logical Screen> <Data>* Trailer

<Logical Screen> ::=      Logical Screen Descriptor [Global Color Table]

<Data> ::=                <Graphic Block>  |
                          <Special-Purpose Block>

<Graphic Block> ::=       [Graphic Control Extension] <Graphic-Rendering Block>

<Graphic-Rendering Block> ::=  <Table-Based Image>  |
                               Plain Text Extension

<Table-Based Image> ::=   Image Descriptor [Local Color Table] Image Data

<Special-Purpose Block> ::=    Application Extension  |
                               Comment Extension

有人用圖片的形式整理了語(yǔ)法,看起來(lái)更直觀:

C#實(shí)現(xiàn)合并多個(gè)圖像文件為一個(gè)動(dòng)態(tài)GIF

其中很多區(qū)塊是可以重復(fù)的,它的圖像數(shù)據(jù)模塊采用了LZW算法,LZW壓縮算法是Compuserv所開(kāi)發(fā)的一種免費(fèi)算法,然而詭異的是這種算法忽然成了Unisys公司的專(zhuān)利,據(jù)Unisys公司稱(chēng),他們已注冊(cè)了LZW算法中的W部分。如果要開(kāi)發(fā)生成(或顯示)圖像互換格式文件的程序,則需向該公司支付版稅。Unisys公司的行為曾引起部份開(kāi)放源代碼社區(qū)發(fā)起“Burn all GIFs”的運(yùn)動(dòng)抵制使用GIF。因此,這刺激CompuServe 公司開(kāi)發(fā)了PNG(Portable Network Graphics,便攜網(wǎng)絡(luò)圖形)標(biāo)準(zhǔn),它一方面滿(mǎn)足了市場(chǎng)對(duì)更少的法規(guī)限制的需要,另一方面也帶來(lái)了更少的技術(shù)上的限制,如顏色的數(shù)量等。

已有實(shí)現(xiàn)

在CodeProject上,有人已經(jīng)實(shí)現(xiàn)了C#版本的GIF圖片生成器,代碼很多,也很好用。但是對(duì)于GIF格式標(biāo)準(zhǔn)不熟悉的人,是看不懂代碼的。它的實(shí)現(xiàn)完全是采用文件流的方式,根據(jù)GIF格式編碼語(yǔ)法,生成文件流,甚至還實(shí)現(xiàn)了LZW算法來(lái)壓縮圖像。因此這個(gè)程序是非常好的學(xué)習(xí)參考資料。

GDI實(shí)現(xiàn)

微軟的GDI(Graphics Device Interface)是一套很好的圖像開(kāi)發(fā)類(lèi)庫(kù),因此本人覺(jué)得為啥那麻煩要用純文件流的方式去創(chuàng)建GIF,直接用GDI方法去創(chuàng)建GIF不就可以了,微軟應(yīng)該提供這方面的接口的。于是網(wǎng)上找到一些示例代碼。實(shí)現(xiàn)動(dòng)態(tài)GIF,有個(gè)方法就是Image.SaveAdd,它可以實(shí)現(xiàn)在現(xiàn)有圖片上再加一幀,可是難點(diǎn)在于設(shè)置延時(shí)時(shí)間。對(duì)于第一幀的延時(shí)的設(shè)置很容易實(shí)現(xiàn),但是對(duì)于第二幀的延時(shí),一直無(wú)效。百思不得其解。

后去Stackoverflow問(wèn)了一下,得到的回復(fù)是微軟GDI不支持這種GIF延時(shí),同樣百思不得其解。

于是只好土洋結(jié)合,對(duì)于生成好的GIF,修改其二進(jìn)制數(shù)據(jù),以此實(shí)現(xiàn)延時(shí)。

用GDI實(shí)現(xiàn)設(shè)置循環(huán)次數(shù)和加入幀的代碼,不算復(fù)雜。C#中可以通過(guò)代碼修改圖片的一些GIF屬性,但是不了解GIF編碼格式的人還是寫(xiě)不出來(lái)的,主要是不知道如何賦值,因?yàn)槲④浌俜轿臋n也沒(méi)給出這部分說(shuō)明。

比如代碼

PropertyItem LoopCount = img.GetPropertyItem(0x5101);//循環(huán)次數(shù) //可以去http://msdn.microsoft.com/en-us/library/system.drawing.imaging.propertyitem.id.aspx/css查詢(xún)
LoopCount.Value = BitConverter.GetBytes(loopCount);
img.SetPropertyItem(LoopCount);

0x5101根據(jù)文檔是循環(huán)次數(shù)的屬性。該屬性設(shè)置循環(huán)次數(shù)。GIF文檔中,該屬性在應(yīng)用擴(kuò)展塊中,占2個(gè)字節(jié)16位,按低位高位的順序排列,是一個(gè)無(wú)符號(hào)的整型。如果01 00表示16進(jìn)制的0x0001,如果設(shè)成00 00 則表示0,循環(huán)無(wú)限次。

循環(huán)次數(shù)可以使用GDI控制,但是延時(shí)時(shí)間在第二幀后就失效了。因此手動(dòng)更改。

延時(shí)時(shí)間的屬性在圖像控制擴(kuò)展塊,對(duì)于每一幀圖像,都有對(duì)應(yīng)的圖像控制擴(kuò)展塊,修改其中的字節(jié)即可。圖像控制擴(kuò)展塊以21 F9開(kāi)頭,在緊挨著的第三第四字節(jié)就是設(shè)置延時(shí)時(shí)間的,單位是百分之一秒。同樣的這2個(gè)字節(jié)也是按低位高位順序排列的,比如是C8 00,則表示0x00C8=200,也就是延時(shí)2秒。

根據(jù)以上理論就可以容易的寫(xiě)出設(shè)置延時(shí)時(shí)間的代碼。

byte[] bytes = File.ReadAllBytes(savefile);
byte[] delaybyte = BitConverter.GetBytes(delay);//轉(zhuǎn)成16位無(wú)符號(hào)字節(jié)數(shù)組。該數(shù)組肯定只有2個(gè)元素
for (int i = 0; i < bytes.Length - 1; i++)
{
     if (bytes[i] == 0x21 && bytes[i + 1] == 0xf9)//GraphicsControlExtension 開(kāi)始標(biāo)志
      {
        bytes[i + 4] = delaybyte[0];//這兩位就是定義延遲時(shí)間的,修改就可以了。
        bytes[i + 5] = delaybyte[1];
        }
}

采用GDI方式,比較簡(jiǎn)單,偷懶,使用微軟做好的現(xiàn)成代碼,再稍稍改動(dòng)就可以了。

參考資料

http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp

http://www.w3.org/Graphics/GIF/spec-gif89a.txt

http://www.codeproject.com/Articles/11505/NGif-Animated-GIF-Encoder-for-NET

http://en.wikipedia.org/wiki/Graphics_Device_Interface

http://www.cnblogs.com/zhengye/articles/2193006.html

《多媒體技術(shù)基礎(chǔ)》 林福宗

附件:http://down.51cto.com/data/2363255
向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI