相信如何为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. [软件推荐]快速文件复制工具(Limit Copy) V4.0 绿色版

    快速文件复制工具(Limit Copy)绿色版是一款智能变频超快复制绿色软件. 快速文件复制工具(Limit Copy)功能比较完善,除了文件复制还可以智能变频,直接把要复制的文件拖入窗口即可,无需手 ...

  2. Hadoop 学习资料集锦

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

  3. java的poi技术写Excel的Sheet

    在这之前写过关于java读,写Excel的blog如下: Excel转Html java的poi技术读,写Excel[2003-2007,2010] java的poi技术读取Excel[2003-20 ...

  4. 使用canal分析binlog(二) canal源码分析

    在能够跑通example后有几个疑问 1. canal的server端对于已经读取的binlog,client已经ack的position,是否持久化,保存在哪里 2. 即使不启动zookeeper, ...

  5. cookie的基本用法案例

    注:cookie必须在服务器环境下有效. 步骤讲解: 1,引入cookie文件: 2,设置过期时间: var date = new Date(); date.setTime(date.getTime( ...

  6. JAVA自定义注解

    在学习使用Spring和MyBatis框架的时候,使用了很多的注解来标注Bean或者数据访问层参数,那么JAVA的注解到底是个东西,作用是什么,又怎样自定义注解呢?这篇文章,即将作出简单易懂的解释. ...

  7. 【WPF】WPF中的List<T>和ObservableCollection<T>

    在WPF中 控件绑定数据源时,数据源建议采用 ObservableCollection<T>集合 ObservableCollection<T> 类:表示一个动态数据集合,在添 ...

  8. zepto区别于jquery获取select表单选中的值

    在jquery下,我们获取select表单选中的值通常是通过$('select').val()来实现,这样的方式简单又明了,或者通过$('select option[selected]').text( ...

  9. phpstudy虚拟机配置

    PHPStudy是一个常用的PHP本地环境搭建的一个程序包,方便实用.对学习PHP的新手来说, WINDOWS下环境配置是一件很困难的事;对老手来说也是一件烦琐的事.因此无论你是新手还是老手,该程序包 ...

  10. 数据库中数据DELETE了怎样恢复

    USE [BBDAS_FP_DATA] GO /****** Object: StoredProcedure [dbo].[Recover_Deleted_Data_Proc] Script Date ...