• 【WP 8.1开发】如何动态生成Gif动画


    相信如何为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(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个字节也没问题的(其实第五个字节是’‘,即NULL,表示结尾)。要实现无限循环播放,只要把下面字节数组写入/appext/Data即可。

    3, 1, 0, 0

    第一个字节为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[] { 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

  • 相关阅读:
    spring学习之@SessionAttributes
    Spring MVC @SessionAttributes注解
    SpringBoot yml 配置 多配置文件,开发环境,生产环境配置文件分开
    java 常用集合list与Set、Map区别及适用场景总结
    JAVA中String.format的用法 格式化字符串,格式化数字,日期时间格式化,
    Spring注解详解@Repository、@Component、@Service 和 @Constroller
    使用idea 在springboot添加本地jar包的方法本地运行有效,一旦需要打jar就会报错,这就需要在
    使用idea 在springboot添加本地jar包的方法 部署的时候本地jar没有包含的解决方法
    IDEA 快速将spring boot项目打包成jar包,简单快速有效
    java 泛型详解-绝对是对泛型方法讲解最详细的,没有之一
  • 原文地址:https://www.cnblogs.com/tcjiaan/p/4190219.html
Copyright © 2020-2023  润新知