Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to display an animated GIF in a Windows Phone 8.1 (RT) application?

I am trying to display a GIF file stored in a Windows Phone 8.1 (RT) application's local folder. Until now, I have tried several approaches:

  1. Load the GIF in a WebView control. This is not a solution since I want to display the images in a FlipView control (I cannot flip to another image). Also, it is quite slow.

  2. Get the GIF frames using the BitmapDecoder class and animate them using a storyboard.

    The code is as follows:

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

The problem is that the frames I get from the GIF image are messed up

like this one

Am I doing something wrong in this approach? What should I modify in order to get good results?

I wouldn't like to use SharpDX since it seems to be very complicated and I am a beginner.

ImageTools is available only for Silverlight

like image 262
rhcpfan Avatar asked Oct 01 '14 11:10

rhcpfan


2 Answers

I made a very basic GifImage control that you can start from. This is a starting point, you'll have to improve it to make it more usable as a reusable control. Check it out here.

GifImage windows phone screenshot


EDIT

Do you have any idea how to improve the loading speed (parallelization, etc.)?

I assume you're referring to the process of preparing the frames. From what I tested, it seems to load instantly anyway, so there shouldn't be a need for drastic performance improvements. However, if perhaps the animation has hundreds of frames, then it could be a bottleneck maybe? More testing needs to be done to assess whether or not optimisations are necessary.

I also don't think it can be paralleled easily since each frame needs to be rendered in sequence from the previous frame. My only suggestion would be to run the loading code on a background thread so the UI thread doesn't block for large images.

If I have this control as a FlipViewItem, how can I release the memory after the item is flipped away?

I'm not sure whether or not you're using MVVM or not, but anyway, here's some suggestions:

  • Set the Source of the GifImage to null if it's not currently visible (inspect the SelectedIndex of the flip view). Note that currently the code in my repo doesn't handle setting Source to null. Like I said before, it needs lots of improvements. You'll have to make sure that the control doesn't hold any references to the frames so that the garbage collector can free them from memory (that is, call animation.KeyFrames.Clear() to clear all references to the frames).
  • Use a VirtualizingStackPanel inside the flip view. This will ensure that only the previous, current, and next flip view items are created in memory. You set it like this:
<FlipView>
    <FlipView.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </FlipView.ItemsPanel>
</FlipView>
like image 74
Decade Moon Avatar answered Oct 17 '22 04:10

Decade Moon


I had a similar problem. I was trying to display an animated GIF loaded from an external source inside a ScrollViewer for Windows Phone 8.1 app. Since the web control takes over the events the scrolling did not work.

I used this trick: I placed the web control inside a grid and put another grid over the webcontrol. The grid over the web control was set to be the exact same size and I set the background to transparent. This way the grid receives the events and the scrolling works again.

<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>
like image 22
MihaS Avatar answered Oct 17 '22 03:10

MihaS