【WP 8.1開發】如何動態生成Gif動畫

相信如何爲gif文件編碼,不少朋友都會,而難點在於怎麼讓GIF文件中的幀動起來,也就是建立gif動畫。數組

 

Gif文件編碼方法

先簡單介紹一下編碼的方法。瀏覽器

一、調用BitmapEncoder.CreateAsync靜態方法實例化編碼器,要建立GIF編碼器,能夠在調用方法時,指定表示GIF編碼器的GUID,這個GUID不用特地去記,由於訪問BitmapEncoder.GifEncoderId靜態屬性就能獲得。數據結構

二、調用SetPixelData方法設置當前幀的圖像數據。注意,編碼器對象在建立實例後,默認處於第一幀,所以對於設置第一張圖片的數據時,能夠直接調用SetPixelData方法。app

三、從第二幀開始,須要先調用GoToNextFrameAsync方法向後移動一幀,而後才調用SetPixelData方法設置數據。設置完最後一幀後就不用再調用GoToNextFrameAsync,由於後面沒有內容了,若是調用GoToNextFrameAsync建立新幀而不寫入數據,會引起異常。dom

四、關閉相關的流。ide

好比下面示例:函數

            BitmapEncoder encoder= await BitmapEncoder.CreateAsync(BitmapEncoder.GifEncoderId, outStream);

                  ……

             encoder.SetPixelData(decoder.BitmapPixelFormat, decoder.BitmapAlphaMode, decoder.PixelWidth, decoder.PixelHeight, decoder.DpiX, decoder.DpiY, data);
               ……
                if ( 不是最後一幀 )
                {
                    await encoder.GoToNextFrameAsync();
                }


設置時間間隔

若是要讓gif產生動畫,就得設置延遲時間,即時間間隔。要經過寫入圖像元數據的方法來實現。動畫

表示時間間隔的元數據路徑爲:ui

            BitmapProperties pv = encoder.BitmapProperties;
            Dictionary<string, BitmapTypedValue> props = new Dictionary<string, BitmapTypedValue>();
            ……

            // Delay表示每一幀的時間間隔,單位爲1/100秒
            props.Add("/grctlext/Delay", new BitmapTypedValue(30, PropertyType.UInt16));
            await pv.SetPropertiesAsync(props); //寫入元數據

元數據能夠用字典數據結構來操做,Key爲字段的路徑,Value就是該元數據的值,由BitmapTypedValue類來封裝元數據值。使用時經過如下構造函數來實例化。編碼

    public BitmapTypedValue ( object value, PropertyType type );

value就是元數據的值,類型爲object,能夠兼容各類值,type參數指定元數據的數據類型,由Windows.Foundation命名空間下的PropertyType枚舉來規範。

Delay的值爲 1 / 100秒,即0.01秒,若是設置爲50,就表示動畫每一個幀的間隔爲50 * 10 = 500毫秒。

 

設置delay後保存的gif文件已經有動畫效果了,可是,它只播放一次就會停下來。多數狀況下,咱們都但願GIF動畫是無限循環播放的,這就要設置其餘的元數據值了。

 

無限循環播放

要讓gif循環播放,須要指定兩個值:

第一個值是 /appext/Application,這個值是必須的,並且是固定的,就是字符串「NETSCAPE2.0」的字節表示形式,注意是字節表示,不要直接設置字符串,該字符串轉化爲字節數組爲11個字節。NetScape有一款瀏覽器,相信不少人都知道,當年我在Win 98下常常用這個瀏覽器的,呵呵,一直用到Win Me還在用。

第二個值是 /appext/Data。在C++中,這個值通常包括5個字節,不過咱們在C#中放4個字節也沒問題的(其實第五個字節是’\0‘,即NULL,表示結尾)。要實現無限循環播放,只要把下面字節數組寫入/appext/Data便可。

3, 1, 0, 0

第一個字節爲3,表示緊跟它後面的字節數,由於後面一、0、0是3個字節,因此它的值爲3。

第二個字節必須爲1,表示啓用gif動畫。

第三個字節表示循環播放的次數。0表示無限循環,若是但願動畫播放5次就停下來,那就設置爲5。一般都爲0,由於咱們都喜歡死循環。

第四個字節爲有效高字位的迭代統計,我也不知道幹嘛用的,反正設置爲0就好了。

其實,若是想讓動畫無限循環,只要記住三、一、0、0四個值就行了,直接背下來也無所謂,反正很好記。

 

 

生成GIF動畫示例

這個示例把5張jpg圖片合起來,變成一個GIF文件,而且有動畫效果的。爲了節省廢話,我只帖上建立GIF的核心代碼。

            StorageFolder photoFolder = KnownFolders.PicturesLibrary;
            StorageFile newFile = await photoFolder.CreateFileAsync("newfile.gif",CreationCollisionOption.ReplaceExisting);
            IRandomAccessStream outStream = await newFile.OpenAsync(FileAccessMode.ReadWrite);
            BitmapEncoder encoder= await BitmapEncoder.CreateAsync(BitmapEncoder.GifEncoderId, outStream);
            // 元數據

            /*
             * /appext/Application的值是固定的,爲「NETSCAPE2.0」,11個字節
             * /appext/Data設置循環播放,若是不設置該字段,則只播放一次。
             * Data的值是一組字節,因爲將第一個字節設置爲3,第二個字節設置爲1便可以達到循環播放效果,
             * 其餘字符能夠爲0;
             * 3 - 表示隨後的字節塊大小,後面1,0,0三個字節,因此爲3;
             * 1 - 表示Gif使用動畫;
             * 0 - 循環次數,0表示無限循環
             */

            BitmapProperties pv = encoder.BitmapProperties;
            Dictionary<string, BitmapTypedValue> props = new Dictionary<string, BitmapTypedValue>();
            byte[] buffer = System.Text.Encoding.UTF8.GetBytes("NETSCAPE2.0");
            // 此字段必須
            props.Add("/appext/Application", new BitmapTypedValue(buffer, PropertyType.UInt8Array));
            // 表示循環播放
            props.Add("/appext/Data", new BitmapTypedValue(new byte[] { 3, 1, 0, 0 }, PropertyType.UInt8Array));

            // Delay表示每一幀的時間間隔,單位爲1/100秒
            props.Add("/grctlext/Delay", new BitmapTypedValue(30, PropertyType.UInt16));
            await pv.SetPropertiesAsync(props); //寫入元數據

            for (short i = 1; i <= 5; i++)
            {
                Uri uri = new Uri("ms-appx:///Assets/" + i.ToString() + ".jpg");
                StorageFile inFile = await StorageFile.GetFileFromApplicationUriAsync(uri);
                IRandomAccessStream inStream = await inFile.OpenReadAsync();
                // 解碼
                BitmapDecoder decoder = await BitmapDecoder.CreateAsync(BitmapDecoder.JpegDecoderId, inStream);
                // 獲取像素數據
                PixelDataProvider pxProvider = await decoder.GetPixelDataAsync();
                byte[] data = pxProvider.DetachPixelData();
                // 編碼
                encoder.SetPixelData(decoder.BitmapPixelFormat, decoder.BitmapAlphaMode, decoder.PixelWidth, decoder.PixelHeight, decoder.DpiX, decoder.DpiY, data);
                inStream.Dispose();
                if (i < 5)
                {
                    await encoder.GoToNextFrameAsync();
                }
            }

            await encoder.FlushAsync();
            outStream.Dispose();

 

下面gif圖片就是用上面的示例建立的,一塊兒來欣賞一下。

 

如何?  這些芙蓉花是否是很美?

 

===============================================

修訂:

可能你們已經發現,上面生成的gif動畫有點小問題,就是後一幀圖片會與上一幀圖片重疊,有時候咱們是但願每一幀圖片獨立顯示。因此在設置元數據時,能夠把 /grctlext/Disposal 的值設置爲2,表示清除上一幀圖片。

props.Add("/grctlext/Disposal", new BitmapTypedValue((byte)2, PropertyType.UInt8));

再看看經過這樣修改後生成的圖片。

如今,每一幀圖片就不會發生重疊了。

 

上面示例的源碼下載:http://files.cnblogs.com/tcjiaan/BuildGifApp.zip

相關文章
相關標籤/搜索