如何在Windows Phone 8.1(RT)应用程序中显示动画GIF?

7
我正在尝试在Windows Phone 8.1 (RT)应用程序的本地文件夹中显示一个GIF文件。到目前为止,我已经尝试了几种方法:
  1. 使用WebView控件加载GIF。这不是一个解决方案,因为我想在FlipView控件中显示图像(我无法翻转到另一张图像)。而且它非常慢。

  2. 使用BitmapDecoder类获取GIF帧,并使用故事板将它们动画化。

    代码如下:

    using (var stream = await storageFile.OpenReadAsync())
    {
        //I don't specify the type since I would like to load other type of images also
        //It doesn't make any difference if I would use "BitmapDecoder.GifDecoderId"
        
        var decoder = await BitmapDecoder.CreateAsync(stream);
        uint frameCount = decoder.FrameCount;

        for (uint frameIndex = 0; frameIndex < frameCount; frameIndex++)
        {
            var frame = await decoder.GetFrameAsync(frameIndex);
            var writableBitmap = new WriteableBitmap((int)decoder.OrientedPixelWidth, 
                                                     (int)decoder.OrientedPixelHeight);

            var pixelDataProvider = await frame.GetPixelDataAsync
               (BitmapPixelFormat.Bgra8,
                decoder.BitmapAlphaMode, new BitmapTransform(),
                ExifOrientationMode.IgnoreExifOrientation, 
                ColorManagementMode.DoNotColorManage);

            var pixelData = pixelDataProvider.DetachPixelData();
            using (var pixelStream = writableBitmap.PixelBuffer.AsStream())
            {
                pixelStream.Write(pixelData, 0, pixelData.Length);
            }

            _bitmapFrames.Add(writableBitmap);
        }
    }

问题是我从GIF图像中获取的帧混乱了。 like this one 我在这个方法中做错了什么吗?我应该修改什么才能得到好的结果?
我不想使用SharpDX,因为它似乎非常复杂,而且我是初学者。
ImageTools仅适用于Silverlight。

现在人们还在使用动态 .gif 吗?我甚至讨厌提议保留它,但你可以只需使用 <MediaElement Source="YourAnimated.gif"/>。不过,如果你想保留它,请告诉我,这样我就可以将其作为答案,以便能够轻松获得一些点数。 :) - Chris W.
1
我尝试将MediaElement添加到页面并将gif文件设置为其源。在将AreTransportControlsEnabled设置为true后,我看到了错误提示“不支持的视频类型或无效的文件路径”。此外,GIF文件的路径已正确设置。 - rhcpfan
我本以为我之前用过它,也许不是 WP?如果有时间,我稍后会调试一下。对此很抱歉。 - Chris W.
1
不过,这并不是一个解决方案。 - rhcpfan
2个回答

6
我制作了一个非常基础的GifImage控件,您可以从中开始。这是一个起点,您需要改进它以使其更可重用和易用的控件。在这里查看。

GifImage windows phone screenshot


编辑

你有什么想法来提高加载速度(并行处理等)吗?

我猜你是指准备动画帧的过程。从我的测试中看,它似乎已经可以立即加载,因此不需要进行大幅度的性能改进。但是,如果动画有数百帧,那么可能会成为瓶颈吗?需要进行更多的测试以评估是否需要优化。

我也不认为它可以轻松地并行处理,因为每个帧都需要按顺序从上一个帧渲染。我的建议是在后台线程上运行加载代码,这样UI线程不会因为大型图像而阻塞。

如果我将此控件作为 FlipViewItem ,那么在翻转掉出视图后如何释放内存?

我不确定你是否在使用MVVM,但无论如何,以下是一些建议:

  • 如果FlipViewSelectedIndex没有选中,将GifImageSource设置为null。请注意,目前我代码库中的代码没有处理将Source设置为null的情况。正如我之前所说,它需要很多改进。您必须确保控件不持有对帧的任何引用,以便垃圾收集器可以从内存中释放它们(也就是调用animation.KeyFrames.Clear()来清除对帧的所有引用)。
  • FlipView中使用VirtualizingStackPanel。这样可以确保仅在内存中创建前一个、当前和下一个翻转视图项。您可以像这样设置它:
<FlipView>
    <FlipView.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </FlipView.ItemsPanel>
</FlipView>

谢谢你的解决方案!我只进行了一些小测试,但它运行良好。你有什么想法可以改善加载速度(并行化等)吗?另外,如果我将此控件作为FlipViewItem,那么在翻转项目后如何释放内存?再次感谢你的时间! - rhcpfan

2

我曾经遇到过类似的问题。我正在尝试在Windows Phone 8.1应用程序的ScrollViewer中显示从外部源加载的动画GIF。由于Web控件接管了事件,因此无法滚动。

我使用了这个技巧:我将Web控件放置在一个网格中,并在Web控件上放置另一个网格。覆盖Web控件的网格设置为完全相同的大小,并将背景设置为透明。这样,网格将接收事件,滚动就能正常工作了。

<ScrollViewer Visibility="Visible" HorizontalAlignment="Left" VerticalAlignment="Top" Width="380">
    <Grid>
        <StackPanel>

            <!--
            Some items ...
            -->

            <Grid >
                <WebView x:Name="animationWebView" HorizontalAlignment="Left" Height="315" Width="390" Visibility="Visible" />
                <Grid Width="390" Height="315" Background="Transparent" />
            </Grid>

            <!--
            Some other items ...
            -->
        </StackPanel>
    </Grid>
</ScrollViewer>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接