首页 > 解决方案 > 在 Image 控件中显示 GIF 的帧

问题描述

我尝试在 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(...))时,窗口冻结并且没有任何反应,我必须终止该进程。在我围绕新源的设置添加Dispatcher.RunAsync(...)之前,我遇到了一个异常“应用程序调用了一个为不同线程编组的接口...... ”。

我不知道是什么原因造成的。也许我需要将字节转换为图像控件可以理解的东西,或者整个像素数据的创建是错误的?

标签: c#uwpuwp-xamlanimated-gifmemorystream

解决方案


这是实现您正在寻找的东西的一种方法:

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;
        }
    }
}

结果:

在此处输入图像描述

至少可以说相当复杂的过程......

原始GIF:

在此处输入图像描述

您的实际错误是您试图提供SetSource原始像素数据流,这不是它所期望的。


推荐阅读