相信如何为gif文件编码,很多朋友都会,而难点在于怎么让GIF文件中的帧动起来,也就是创建gif动画。

Gif文件编码方法

先简单介绍一下编码的方法。

1、调用BitmapEncoder.CreateAsync静态方法实例化编码器,要创建GIF编码器,可以在调用方法时,指定表示GIF编码器的GUID,这个GUID不用特意去记,因为访问BitmapEncoder.GifEncoderId静态属性就能得到。

2、调用SetPixelData方法设置当前帧的图像数据。注意,编码器对象在创建实例后,默认处于第一帧,因此对于设置第一张图片的数据时,可以直接调用SetPixelData方法。

3、从第二帧开始,需要先调用GoToNextFrameAsync方法向后移动一帧,然后才调用SetPixelData方法设置数据。设置完最后一帧后就不用再调用GoToNextFrameAsync,因为后面没有内容了,如果调用GoToNextFrameAsync创建新帧而不写入数据,会引发异常。

4、关闭相关的流。

比如下面示例:

            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产生动画,就得设置延迟时间,即时间间隔。要通过写入图像元数据的方法来实现。

表示时间间隔的元数据路径为:

            BitmapProperties pv = encoder.BitmapProperties;
Dictionary<string, BitmapTypedValue> props = new Dictionary<string, BitmapTypedValue>();
…… // Delay表示每一帧的时间间隔,单位为1/100秒
props.Add("/grctlext/Delay", new BitmapTypedValue(, 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个字节,所以它的值为3。

第二个字节必须为1,表示启用gif动画。

第三个字节表示循环播放的次数。0表示无限循环,如果希望动画播放5次就停下来,那就设置为5。通常都为0,因为我们都喜欢死循环。

第四个字节为有效高字位的迭代统计,我也不知道干吗用的,反正设置为0就行了。

其实,如果想让动画无限循环,只要记住3、1、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[] { , , , }, PropertyType.UInt8Array)); // Delay表示每一帧的时间间隔,单位为1/100秒
props.Add("/grctlext/Delay", new BitmapTypedValue(, PropertyType.UInt16));
await pv.SetPropertiesAsync(props); //写入元数据 for (short i = ; i <= ; 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 < )
{
await encoder.GoToNextFrameAsync();
}
} await encoder.FlushAsync();
outStream.Dispose();

下面gif图片就是用上面的示例创建的,一起来欣赏一下。

如何?  这些芙蓉花是不是很美?

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

修订:

可能大家已经发现,上面生成的gif动画有点小问题,就是后一帧图片会与上一帧图片重叠,有时候我们是希望每一帧图片独立显示。所以在设置元数据时,可以把 /grctlext/Disposal 的值设置为2,表示清除上一帧图片。

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

再看看通过这样修改后生成的图片。

现在,每一帧图片就不会发生重叠了。

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

【WP 8.1开发】如何动态生成Gif动画的更多相关文章

  1. 基于webpack的前端工程化开发解决方案探索(一):动态生成HTML(转)

    1.什么是工程化开发 软件工程的工程化开发概念由来已久,但对于前端开发来说,我们没有像VS或者eclipse这样量身打造的IDE,因为在大多数人眼中,前端代码无需编译,因此只要一个浏览器来运行调试就行 ...

  2. Unity3D独立游戏开发日记(一):动态生成树木

    目前写的独立游戏是一个沙盒类型的游戏.游戏DEMO视频如下: 提到沙盒类型的游戏,就有人给出了这样的定义: 游戏世界离现实世界越近,自由度.随机度越高才叫沙盒游戏.所谓自由度,就是你在游戏里想干啥就干 ...

  3. C# 动态生成word文档 [C#学习笔记3]关于Main(string[ ] args)中args命令行参数 实现DataTables搜索框查询结果高亮显示 二维码神器QRCoder Asp.net MVC 中 CodeFirst 开发模式实例

    C# 动态生成word文档 本文以一个简单的小例子,简述利用C#语言开发word表格相关的知识,仅供学习分享使用,如有不足之处,还请指正. 在工程中引用word的动态库 在项目中,点击项目名称右键-- ...

  4. Nginx 整合 Lua 实现动态生成缩略图

    原文地址:Nginx 整合 Lua 实现动态生成缩略图 博客地址:http://www.extlight.com 一.前提 最近在开发一个项目,涉及到缩略图的功能,常见的生成缩略图的方案有以下几个: ...

  5. 【WP 8.1开发】How to 图像处理

    在今天的吹牛节目开始之前,先交代一件事: 关于玩WP 8.1开发所使用的VS版本问题.对版本的要求是2013的Update2,这是最低要求,只要是这个版本或以上都可以,而update3,update4 ...

  6. ios 开发中 动态库 与静态库的区别

    使用静态库的好处 1,模块化,分工合作 2,避免少量改动经常导致大量的重复编译连接 3,也可以重用,注意不是共享使用 动态库使用有如下好处: 1使用动态库,可以将最终可执行文件体积缩小 2使用动态库, ...

  7. 在后台代码中动态生成pivot项并设置EventTrigger和Action的绑定

    最近在做今日头条WP的过程中,遇到需要动态生成Pivot项的问题.第一个版本是把几个频道写死在xaml里了,事件绑定也写在xaml里,每个频道绑定一个ObservableCollection<A ...

  8. MVC5+EF6 入门完整教程13 -- 动态生成多级菜单

    稍微有一定复杂性的系统,多级菜单都是一个必备组件. 本篇专题讲述如何生成动态多级菜单的通用做法. 我们不用任何第三方的组件,完全自己构建灵活通用的多级菜单. 需要达成的效果:容易复用,可以根据mode ...

  9. MVC 5 + EF6 入门完整教程14 -- 动态生成面包屑导航

    上篇文章我们完成了 动态生成多级菜单 这个实用组件. 本篇文章我们要开发另一个实用组件:面包屑导航. 面包屑导航(BreadcrumbNavigation)这个概念来自童话故事"汉赛尔和格莱 ...

随机推荐

  1. RNN求解过程推导与实现

    RNN求解过程推导与实现 RNN LSTM BPTT matlab code opencv code BPTT,Back Propagation Through Time. 首先来看看怎么处理RNN. ...

  2. Hadoop 学习资料集锦

    Hadoop 资料 虾皮系列教程. Sqoop 资料 官方安装文档. 浪迹天涯博客. 瀚海星空博客. ……

  3. 1.2 控制器 view 的创建和加载

    本文并非最终版本,如有更新或更正会第一时间置顶,联系方式详见文末 如果觉得本文内容过长,请前往本人 “简书”       加载优先顺序: 1.用系统的loadView方法创建控制器的视图 2.如果指定 ...

  4. Android 腾讯入门教程( 智能手表UI设计 和 MVC模式 )

    *****注意到mvc 在android 中是如何进行分层分域执行各自的功能.**** 官方推荐的按钮尺寸是48像素 前端之Android入门(1):环境配置 前端之Android入门(2):程序目录 ...

  5. 使用 Graphviz 画拓扑图

    使用 Graphviz 画拓扑图 0)前述 本文着重讲一下 Graphviz 的风格控制,基础一些的就不在这里讲啦. graphviz 的主页是http://www.graphviz.org/. Gr ...

  6. java分享第十八天-02( java结合testng,利用XML做数据源的数据驱动)

    testng的功能很强大,利用@DataProvider可以做数据驱动,数据源文件可以是EXCEL,XML,YAML,甚至可以是TXT文本.在这以XML为例:备注:@DataProvider的返回值类 ...

  7. 问题2: 安装cocoaPods出现的一系列问题

    在新电脑上安装cocoaPods的时候,出现了一系列的问题,现在记录下来,方便查看 1.出现 Invalid mark letter (press RETURN) 解决方案:输入 :wq 即可 2.  ...

  8. PHP:函数赋参数默认初值

    函数的默认参数 允许定义函数时,指定参数的默认值,如: function js_location($url, $alert='', $top=''){ if($alert=='' && ...

  9. linux一句话轻松提权

    linux命令:‍ [b@fuckks~]$ printf "install uprobes /bin/sh" > exploit.conf; MODPROBE_OPTI** ...

  10. 破除Odoo 菜单栏提示 99+

    菜单栏提示利用的menu对象的needaction_counter属性,默认只能显示99个 多于99则显示99+ 如果希望显示完整的数字,则需要改动如下两个地方. 一.menu菜单的显示限制: 将第一 ...