设为首页 加入收藏

TOP

[UWP]缓存Lottie动画帧(一)
2019-09-17 17:03:01 】 浏览:33
Tags:UWP 缓存 Lottie 动画

在上一篇博文《[UWP]在UWP平台中使用Lottie动画》中我简单介绍了一下LottieUWP项目以及如何使用它呈现Lottie动画,这篇文章里我们来讲点进阶的东西——缓存Lottie动画帧。

为什么会有这样的需求呢?

有两方面原因:

  • 直接在XAML中使用Lottie动画时,是边播放边渲染,计算量比较大,某些Lottie文件会非常吃性能!另外也会存在渲染不正确(有黑色区域)的情况,但是如果我们把每一帧缓存下来,自己控制播放的话,性能会提升很多!
  • 应用于视频合成时(给视频添加Lottie动画挂件),需要获取每一时刻的动画帧图像(UWP媒体编辑以及视频合成的相关知识也很多,有时间我会整理一下,分享点干货)。

获取Lottie动画帧

在上一篇中我们使用了LottieAnimationView控件来播放Lottie动画,其实另一个类LottieDrawable也可以完成同样的工作,并且更易扩展。

下面我们就来修改下LottieDrawable类,让它可以返回给我们某一时刻的帧图像。

LottieDrawable类中,Lottie动画的播放进度由Progress属性控制,而实际上的呈现则是使用了Win2D中的CanvasAnimatedControl控件来承载绘制目标。

这样的话,其实我们要做的就很简单了。我们可以新增一个GetCurrentFrame方法,使用CanvasRenderTarget作为绘制目标,将CanvasAnimatedControl的Draw事件中的绘制逻辑转移过来即可。

具体代码如下:

        /// <summary>
        /// 获取当前进度时的Lottie图像
        /// </summary>
        /// <param name="resourceCreator"></param>
        /// <param name="scaleX">横向缩放倍数</param>
        /// <param name="scaleY">纵向缩放倍数</param>
        /// <returns></returns>
        public CanvasBitmap GetCurrentFrame(ICanvasResourceCreator resourceCreator, float scaleX, float scaleY)
        {
            lock (this)
            {
                var width = _composition.Bounds.Width * scaleX;
                var height = _composition.Bounds.Height * scaleY;
                var commandList = new CanvasRenderTarget(resourceCreator, (float)width, (float)height, 96f);
                using (var session = commandList.CreateDrawingSession())
                {

                    if (_bitmapCanvas == null || _bitmapCanvas.Width < width || _bitmapCanvas.Height < height)
                    {
                        _bitmapCanvas?.Dispose();
                        _bitmapCanvas = new BitmapCanvas(width, height);
                    }

                    using (_bitmapCanvas.CreateSession(resourceCreator.Device, (float)width,
                        (float)height, session))
                    {
                        _bitmapCanvas.Clear(Colors.Transparent);
                        LottieLog.BeginSection("Drawable.Draw");
                        if (_compositionLayer == null)
                        {
                            return null;
                        }

                        _matrix.Reset();
                        _matrix = MatrixExt.PreScale(_matrix, scaleX, scaleY);
                        _compositionLayer.Draw(_bitmapCanvas, _matrix, _alpha);
                        LottieLog.EndSection("Drawable.Draw");
                    }

                }

                return commandList;
            }
        }

有一点要注意的是这里的绘制目标使用了CanvasRenderTarget,切勿使用CanvasCommandList,区别在于CanvasRenderTarget有固定大小的尺寸,而CanvasCommandList则没有固定的尺寸(实际上时无限大的),使用CanvasCommandList作为绘制目标将会引起某些Lottie动画绘制时丢失部分内容,具体可参见我在LottieUWP项目上提的这个Issue

缓存Lottie动画帧

有了上面添加的GetCurrentFrame方法后,我们就可以通过修改Progress来获取Lottie动画中每一时刻的帧图像了。

我编写了一个缓存Lottie动画帧的方法:

        protected List<CanvasBitmap> CacheLottieFrames;
        /// <summary>
        /// 缓存Lottie动画帧
        /// </summary>
        /// <param name="width">缓存图像的宽</param>
        /// <param name="height">缓存图像的高</param>
        /// <param name="frameRate">缓存的帧率</param>
        /// <returns></returns>
        private async Task InitLottieFrame(double width, double height, int frameRate)
        {
            await Task.Run(() =>
            {
                lock (_lockObj)
                {
                    if (lottieDrawable != null)
                    {
                        var duration = lottieDrawable.Composition.Duration;
                        var scaleX = width / lottieDrawable.Composition.Bounds.Width;
                        var scaleY = height / lottieDrawable.Composition.Bounds.Height;
                        var timeGap = 1d / frameRate;
                        CacheLottieFrames = new List<CanvasBitmap>();
                        var device = CanvasDevice.GetSharedDevice();
                        for (var i = 0d; i < duration; i += timeGap)
                        {
                            lottieDrawable.Progress = (floa
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Entityframework Migrations 下一篇二分搜索算法

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目