在图像控件中显示 GIF 帧
Show frame of GIF in Image control
我尝试在 Image 控件中显示加载的 gif 图像(来自文件)的单帧。我在 Image 控件中显示(完整)gif 图像没有问题,但我无法显示框架。出于测试目的,我总是尝试加载帧“0”(第一帧)。
XAML:
<Image>
<Image.Source>
<BitmapImage x:Name="GifFrame" AutoPlay="False" />
</Image.Source>
</Image>
我真的没有在网上找到太多关于如何执行此操作的信息,但这里有一些代码片段,不幸的是,有些可能来自 WPF,我不能 100% 确定它们是否也可以用于 UWP。
当图像打开时调用以下“_OnImageOpened”方法(_gifStream 是打开的 gif 图像,流尚未关闭):
private IRandomAccessStream _gifStream = null;
private async void GifImage_OnImageOpened(object sender, RoutedEventArgs e)
{
// ...
uint frameCount = 0;
if (_gifStream != null)
{
var decoder = await BitmapDecoder.CreateAsync(_gifStream);
frameCount = decoder.FrameCount;
var frame = await decoder.GetFrameAsync(0);
// Create frame image
var pixelData = await frame.GetPixelDataAsync(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied,
new BitmapTransform(),
ExifOrientationMode.IgnoreExifOrientation,
ColorManagementMode.DoNotColorManage
).AsTask().ConfigureAwait(false);
var frameBytes = pixelData.DetachPixelData();
var memoryStream = new MemoryStream(frameBytes);
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
GifFrame.SetSource(memoryStream.AsRandomAccessStream());
});
}
}
当我设置新源时 (GifFrame.SetSource(...)) window 冻结并且没有任何反应,我必须终止进程.在我围绕新源的设置添加 Dispatcher.RunAsync(...) 之前,我遇到了一个异常“应用程序调用了一个接口,该接口被编组为一个不同的线程...".
我不知道是什么原因造成的。也许我需要将字节转换成图像控件可以理解的东西,或者整个像素数据的创建是错误的?
这里有一种方法可以达到您的要求:
XAML:
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<StackPanel>
<Button Content="Open" Click="Button_Click" />
<Image x:Name="Image" Width="100" Height="100" />
</StackPanel>
</Grid>
</Page>
代码:
using System;
using Windows.Graphics.Imaging;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media.Imaging;
namespace App1
{
public sealed partial class MainPage
{
public MainPage()
{
InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
var picker = new FileOpenPicker();
picker.FileTypeFilter.Add(".gif");
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
var file = await picker.PickSingleFileAsync();
if (file == null)
return;
var stream = await file.OpenAsync(FileAccessMode.Read);
var decoder = await BitmapDecoder.CreateAsync(stream);
var frame = await decoder.GetFrameAsync(0);
var softwareBitmap = await frame.GetSoftwareBitmapAsync();
var convert = SoftwareBitmap.Convert(softwareBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
var softwareBitmapSource = new SoftwareBitmapSource();
await softwareBitmapSource.SetBitmapAsync(convert);
Image.Source = softwareBitmapSource;
}
}
}
结果:
至少可以说是相当复杂的过程...
原图:
您的实际错误是您试图向 SetSource
提供像素数据的原始流,这不是 what it expects。
我尝试在 Image 控件中显示加载的 gif 图像(来自文件)的单帧。我在 Image 控件中显示(完整)gif 图像没有问题,但我无法显示框架。出于测试目的,我总是尝试加载帧“0”(第一帧)。
XAML:
<Image>
<Image.Source>
<BitmapImage x:Name="GifFrame" AutoPlay="False" />
</Image.Source>
</Image>
我真的没有在网上找到太多关于如何执行此操作的信息,但这里有一些代码片段,不幸的是,有些可能来自 WPF,我不能 100% 确定它们是否也可以用于 UWP。
当图像打开时调用以下“_OnImageOpened”方法(_gifStream 是打开的 gif 图像,流尚未关闭):
private IRandomAccessStream _gifStream = null;
private async void GifImage_OnImageOpened(object sender, RoutedEventArgs e)
{
// ...
uint frameCount = 0;
if (_gifStream != null)
{
var decoder = await BitmapDecoder.CreateAsync(_gifStream);
frameCount = decoder.FrameCount;
var frame = await decoder.GetFrameAsync(0);
// Create frame image
var pixelData = await frame.GetPixelDataAsync(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied,
new BitmapTransform(),
ExifOrientationMode.IgnoreExifOrientation,
ColorManagementMode.DoNotColorManage
).AsTask().ConfigureAwait(false);
var frameBytes = pixelData.DetachPixelData();
var memoryStream = new MemoryStream(frameBytes);
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
GifFrame.SetSource(memoryStream.AsRandomAccessStream());
});
}
}
当我设置新源时 (GifFrame.SetSource(...)) window 冻结并且没有任何反应,我必须终止进程.在我围绕新源的设置添加 Dispatcher.RunAsync(...) 之前,我遇到了一个异常“应用程序调用了一个接口,该接口被编组为一个不同的线程...".
我不知道是什么原因造成的。也许我需要将字节转换成图像控件可以理解的东西,或者整个像素数据的创建是错误的?
这里有一种方法可以达到您的要求:
XAML:
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<StackPanel>
<Button Content="Open" Click="Button_Click" />
<Image x:Name="Image" Width="100" Height="100" />
</StackPanel>
</Grid>
</Page>
代码:
using System;
using Windows.Graphics.Imaging;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media.Imaging;
namespace App1
{
public sealed partial class MainPage
{
public MainPage()
{
InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
var picker = new FileOpenPicker();
picker.FileTypeFilter.Add(".gif");
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
var file = await picker.PickSingleFileAsync();
if (file == null)
return;
var stream = await file.OpenAsync(FileAccessMode.Read);
var decoder = await BitmapDecoder.CreateAsync(stream);
var frame = await decoder.GetFrameAsync(0);
var softwareBitmap = await frame.GetSoftwareBitmapAsync();
var convert = SoftwareBitmap.Convert(softwareBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
var softwareBitmapSource = new SoftwareBitmapSource();
await softwareBitmapSource.SetBitmapAsync(convert);
Image.Source = softwareBitmapSource;
}
}
}
结果:
至少可以说是相当复杂的过程...
原图:
您的实际错误是您试图向 SetSource
提供像素数据的原始流,这不是 what it expects。