Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET - Creating a looping .gif using GifBitmapEncoder

I'm trying to write some code to export animated .gifs from a WPF application using GifBitmapEncoder. What I have so far works fine but when I view the resulting .gif it only runs once and then stops - I'd like to have it looping indefinitely.

I've found this previous similar question:

How do I make a GIF repeat in loop when generating with BitmapEncoder

However, he is using the BitmapEncoder from Windows.Graphics.Imaging rather than the Windows.Media.Imaging version, which seems to be a bit different. Nonetheless, that gave me a direction and after a bit more googling I came up with this:

Dim encoder As New GifBitmapEncoder
Dim metaData As New BitmapMetadata("gif")
metaData.SetQuery("/appext/Application", System.Text.Encoding.ASCII.GetBytes("NETSCAPE2.0"))
metaData.SetQuery("/appext/Data", New Byte() {3, 1, 0, 0, 0})

'The following line throws the exception "The designated BitmapEncoder does not support global metadata.":
'encoder.Metadata = metaData

If DrawingManager.Instance.SelectedFacing IsNot Nothing Then
   For Each Frame As Frame In DrawingManager.Instance.SelectedFacing.Frames
       Dim bmpFrame As BitmapFrame = BitmapFrame.Create(Frame.CombinedImage, Nothing, metaData, Nothing)
       encoder.Frames.Add(bmpFrame)
   Next
End If

Dim fs As New FileStream(newFileName, FileMode.Create)
encoder.Save(fs)
fs.Close()

Initially I tried adding the metadata directly to the encoder (as in the commented-out line in the code above), but at runtime that throws the exception "The designated BitmapEncoder does not support global metadata". I can instead attach my metadata to each frame, but although that doesn't crash it the resultant .gif doesn't loop either (and I would expect that the looping metadata would need to be global anyway).

Can anyone offer any advice?

like image 463
Paul Jeffries Avatar asked Sep 10 '13 12:09

Paul Jeffries


People also ask

How do I make a GIF loop in Windows?

Go to "Window" > "Render Queue", and click on the "Format" to select "Animated GIF." Then choose the quality of your GIF loop from the new option windows, and go to the bottom right corner of the screen, select the "Looping" option, and press "OK".

What is looping GIF?

Online GIF loop editor GIF animations can be set to loop (repeat the animation) forever, or for any number of predefined times. It also supports animated PNG (APNG), animated WebP, MNG and FLIF files.


1 Answers

I finally got this to work after studying this article and referencing the raw bytes of GIF files. If you want to do so yourself, you can get the bytes in hex format using PowerShell like so...

$bytes = [System.IO.File]::ReadAllBytes("C:\Users\Me\Desktop\SomeGif.gif")
[System.BitConverter]::ToString($bytes)

The GifBitmapEncoder appears to write the Header, Logical Screen Descriptor, then the Graphics Control Extension. The "NETSCAPE2.0" extension is missing. In GIFs from other sources that do loop, the missing extension always appears right before the Graphics Control Extension.

So I just plugged in the bytes after the 13th byte, since the first two sections are always this long.

        // After adding all frames to gifEncoder (the GifBitmapEncoder)...
        using (var ms = new MemoryStream())
        {
            gifEncoder.Save(ms);
            var fileBytes = ms.ToArray();
            // This is the NETSCAPE2.0 Application Extension.
            var applicationExtension = new byte[] { 33, 255, 11, 78, 69, 84, 83, 67, 65, 80, 69, 50, 46, 48, 3, 1, 0, 0, 0 };
            var newBytes = new List<byte>();
            newBytes.AddRange(fileBytes.Take(13));
            newBytes.AddRange(applicationExtension);
            newBytes.AddRange(fileBytes.Skip(13));
            File.WriteAllBytes(saveFile, newBytes.ToArray());
        }
like image 142
Jared Avatar answered Oct 03 '22 05:10

Jared