Показать кадр GIF в управлении изображениями - PullRequest
2 голосов
/ 02 апреля 2019

Я пытаюсь показать один кадр загруженного изображения GIF (из файла) внутри элемента управления изображения. У меня нет проблем с отображением (полного) изображения 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 (...) вокруг настройки нового источника, я получил исключение " Приложение называло интерфейс, который был назначен для другого потока ... ».

Я понятия не имею, что вызывает это. Может быть, мне нужно преобразовать байты во что-то, что может понять элемент управления изображением, или, может быть, создание целых пиксельных данных неверно?

1 Ответ

1 голос
/ 02 апреля 2019

Вот один из способов добиться того, что вы ищете:

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

Результат:

enter image description here

Совершенно запутанный процесс, если не сказать больше ...

Оригинальный GIF:

enter image description here

Ваша настоящая ошибка в том, что вы пытаетесь передать SetSource необработанным потоком данных пикселей, это не , что он ожидает .

...