我正在尝试显示存储在Windows Phone 8.1( RT )应用程序的本地文件夹中的 GIF文件。到现在为止,我尝试了几种方法:
使用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图像中得到的帧是搞砸了
这种方法我做错了吗?为了获得好结果,我应该修改什么?
我不想使用SharpDX,因为它看起来非常复杂,我是初学者。
ImageTools仅适用于Silverlight
答案 0 :(得分:6)
我制作了一个非常基本GifImage
控件,您可以从中开始。 这是一个起点,您必须对其进行改进,使其更适合作为可重复使用的控件。请查看here。
修改强>
您是否知道如何提高加载速度(并行化等)?
我假设你指的是准备帧的过程。从我测试的结果来看,它似乎无论如何都会立即加载,因此不需要进行大幅度的性能改进。但是,如果动画可能有数百帧,那么它可能是一个瓶颈?需要进行更多测试以评估是否有必要进行优化。
我也不认为它可以很容易并行,因为每个帧都需要从前一帧按顺序渲染。我唯一的建议是在后台线程上运行加载代码,这样UI线程就不会阻塞大图像。
如果我将此控件设为
FlipViewItem
,如何在项目被翻转后释放内存?
我不确定您是否使用MVVM,但无论如何,这里有一些建议:
Source
的{{1}}当前不可见,请设置为GifImage
(检查翻转视图的SelectedIndex
)。请注意,目前我的repo中的代码不会将Source
设置为null。就像我之前说的那样,它需要很多改进。您必须确保控件不保留对帧的任何引用,以便垃圾收集器可以从内存中释放它们(即,调用animation.KeyFrames.Clear()
以清除对帧的所有引用)。VirtualizingStackPanel
。这将确保仅在内存中创建先前,当前和下一个翻转视图项。你这样设置:<FlipView>
<FlipView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</FlipView.ItemsPanel>
</FlipView>
答案 1 :(得分:2)
我有类似的问题。我试图在ScrollViewer for Windows Phone 8.1应用程序中显示从外部源加载的动画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>