Convert a Multipage Image to Reverse Animated GIF - WinForms C# .NET 6

This tutorial shows how to load a multipage image, reverse the order of its pages, and export the file to an animated GIF in a WinForms C# application using the LEADTOOLS SDK.

Overview  
Summary This tutorial covers how to reverse multipage images and export them as animated GIF images in a WinForms C# Application.
Completion Time 45 minutes
Visual Studio Project Download tutorial project (10 KB)
Platform Windows WinForms C# Application
IDE Visual Studio 2022
Development License Download LEADTOOLS

Required Knowledge

Get familiar with the basic steps of creating a project by reviewing the Add References and Set a License tutorial, before working on the Convert a Multipage Image to Reverse Animated GIF - WinForms C# tutorial.

Also review the Display Images in an Image Viewer tutorial for details on working with WinForms menus and events.

Create the Project and Add LEADTOOLS References

Start with a copy of the project created in the Add References and Set a License tutorial. If you do not have that project, follow the steps in that tutorial to create it.

The references needed depend upon the purpose of the project. References can be added by one or the other of the following two methods (but not both).

If using NuGet references, this tutorial requires the following NuGet package:

If using local DLL references, the following DLLs are needed.

The DLLs are located at <INSTALL_DIR>\LEADTOOLS23\Bin\net:

For a complete list of which DLL files are required for your application, refer to Files to be Included With Your Application.

Set the License File

The License unlocks the features needed for the project. It must be set before any toolkit function is called. For details, including tutorials for different platforms, refer to Setting a Runtime License.

There are two types of runtime licenses:

Note: Adding LEADTOOLS NuGet and local references and setting a license are covered in more detail in the Add References and Set a License tutorial.

Initialize the Picture Box Control

With the project created, the references added, and the license set, coding can begin.

In Solution Explorer, double-click Form1.cs to display it in the Designer. Click the Events icon in the Properties Windows. Then, double-click the Load event to create an event handler if one does not already exist. This will bring up the code behind the form.

Add the using statements below to the top.

C#
using Leadtools; 
using Leadtools.Controls; 
using Leadtools.Codecs; 
using Leadtools.Drawing; 

Add the follow global variables to the Form class.

C#
private RasterPictureBox _pictureBox; 
RasterImage _forwardImage = null; 
RasterImage _reversedImage = null; 
CodecsImageInfo _imageInfo; 

Add the following code inside the Form1_Load event handler to initialize the RasterPictureBox object.

C#
private void Form1_Load(object sender, EventArgs e) 
{ 
   _pictureBox = new RasterPictureBox(); 
   _pictureBox.SizeMode = RasterPictureBoxSizeMode.Fit; 
   _pictureBox.AutoDisposeImage = false; 
 
   RasterPaintProperties paintProperties = _pictureBox.PaintProperties; 
   paintProperties.PaintEngine = RasterPaintEngine.GdiPlus; 
   _pictureBox.PaintProperties = paintProperties; 
 
   _pictureBox.Dock = DockStyle.Fill; 
   _pictureBox.BackColor = Color.DarkGray; 
   Controls.Add(_pictureBox); 
   _pictureBox.BringToFront(); 
} 

Add the Code to Load and Animate Files

Open Form1.cs in the Solution Explorer. Go to the Toolbox and double-click MenuStrip, which will add a menu to the form. Add a File dropdown menu. Make sure the text of the dropdown menu is &File. Inside the File dropdown, add a new MenuItem, with the text &Open. Leave the new item's name as openToolStripMenuItem.

Double-click the Open menu item to create its event handler.

Add the following code to the openToolStripMenuItem_Click event handler to load your input file.

C#
private void OpenToolStripMenuItem_Click(object sender, EventArgs e) 
{ 
   { 
      try 
      { 
         using (RasterCodecs codecs = new RasterCodecs()) 
         { 
            OpenFileDialog dlg = new OpenFileDialog(); 
            dlg.Filter = "GIF image|*.gif|All files|*.*"; 
            if (dlg.ShowDialog(this) == DialogResult.OK) 
            { 
               var info = codecs.GetInformation(dlg.FileName, true); 
               if(info.TotalPages < 2) 
               { 
                  MessageBox.Show("File doesn't have multiple frames. Not loaded."); 
                  return; 
               } 
               _imageInfo = info; 
               var loadedImage = codecs.Load(dlg.FileName, 0, CodecsLoadByteOrder.BgrOrGray, 1, -1); 
               AnimateAndReverse(loadedImage); 
               _pictureBox.Image = _forwardImage; 
               _pictureBox.StopAnimation(); 
            } 
         } 
      } 
      catch (Exception ex) 
      { 
         MessageBox.Show(ex.ToString()); 
      } 
   } 
} 

Add three new methods to the Form1 class named SetGifProperties(RasterImage image), FlattenAndReverse(RasterImage inputImage), and AnimateAndReverse(RasterImage originalImage). Call the AnimateAndReverse() method inside the openToolStripMenuItem_Click event handler, as shown above. Call the SetGifProperties() and FlattenAndReverse() methods inside the AnimateAndReverse() method, as shown below.

Add the following code to the respective methods to animate the loaded image if it is not already animated, and to create a reversed, flattened copy of the animated image.

C#
private void AnimateAndReverse(RasterImage originalImage) 
{ 
   for (int i = 1; i <= originalImage.PageCount; i++) 
   { 
      originalImage.Page = i; 
      // If frame has no delay, add a default value 
      if (originalImage.AnimationDelay == 0) 
         originalImage.AnimationDelay = 50; 
   } 
   // If original image wasn't animated, save then load GIF to animate it 
   if (!_imageInfo.Gif.HasAnimationLoop) 
      originalImage = SetGifProperties(originalImage); 
 
   _forwardImage = originalImage; 
   _forwardImage.Page = 1; 
   var tmpImage = FlattenAndReverse(originalImage); 
   _reversedImage = SetGifProperties(tmpImage); 
} 
C#
private RasterImage SetGifProperties(RasterImage image) 
{ 
   using RasterCodecs codecs = new(); 
   // Save as GIF and reload to easily set animation properites  
   MemoryStream ms = new(); 
   image.Page = 1; 
   codecs.Save(image, ms, RasterImageFormat.Gif, 8); 
   ms.Position = 0; 
   _imageInfo = codecs.GetInformation(ms, true); 
   image = codecs.Load(ms, 24, CodecsLoadByteOrder.BgrOrGray, 1, -1); 
   ms.Dispose(); 
   return image; 
} 
C#
private RasterImage FlattenAndReverse(RasterImage inputImage) 
{ 
   int w = inputImage.AnimationGlobalSize.Width, h = inputImage.AnimationGlobalSize.Height; 
   if (w <= 0) 
         w = inputImage.Width; 
   if (h <= 0) 
         h = inputImage.Height; 
   RasterImage renderImage = new( 
      RasterMemoryFlags.Conventional, 
      w, 
      h, 
      inputImage.BitsPerPixel, 
      inputImage.Order, 
      inputImage.ViewPerspective, 
      null, 
      IntPtr.Zero, 
      0); 
   // Copy the palette from the animated image to this newly created image  
   inputImage.CopyPaletteTo(renderImage); 
   RasterImage flatImage = null; 
   // Create the RasterImageAnimator object  
   RasterImageAnimator _animator = new RasterImageAnimator(renderImage, inputImage); 
   // Animate it and save the frames in reverse order  
   // Use GDI+ paint engine to support transparent colors  
   RasterPaintProperties props = _pictureBox.PaintProperties; 
   props.PaintEngine = RasterPaintEngine.GdiPlus; 
   using (RasterImageGdiPlusGraphicsContainer _gdiPlusGraphics = new RasterImageGdiPlusGraphicsContainer(renderImage)) 
   { 
         Graphics g = _gdiPlusGraphics.Graphics; 
         RasterImageAnimatorState state; 
 
         bool done = false; 
         while (!done) 
         { 
            LeadRect srcRect = new(0, 0, renderImage.ImageWidth, renderImage.ImageHeight); 
            LeadRect updateRect; 
            LeadRect destRect; 
 
            state = _animator.Process(); 
 
            switch (state) 
            { 
               case RasterImageAnimatorState.WaitDelay: 
               case RasterImageAnimatorState.WaitInputDelay: 
                     // Set the animation delay into the last frame that got inserted  
                     flatImage.AnimationDelay = _animator.Delay; 
                     _animator.CancelWait(); 
                     break; 
               case RasterImageAnimatorState.Render: 
                     break; 
               case RasterImageAnimatorState.WaitInput: 
                     // In case the animated image has the "wait for user input" flags,  
                     // Cancel the waiting  
                     _animator.CancelWait(); 
                     break; 
               case RasterImageAnimatorState.PostRender: 
                     // Get the area in the target image that has changed  
                     updateRect = _animator.GetUpdateRectangle(true); 
                     destRect = new LeadRect(0, 0, renderImage.ImageWidth, renderImage.ImageHeight); 
                     // Paint it  
                     RasterImagePainter.Paint(renderImage, g, srcRect, updateRect, destRect, destRect, props); 
                     if (flatImage == null) 
                        flatImage = renderImage.Clone(); 
                     else 
                        flatImage.InsertPage(0, renderImage.Clone()); // Insert at the beginning to reverse the frames  
                     flatImage.Page = 1; // The newly inserted frame is always number 1  
                     flatImage.AnimationDelay = 50; // Set value in case the animation doesn't provide one.  
                     break; 
               case RasterImageAnimatorState.End: 
                     done = true; // Exist the loop once animation is done  
                     break; 
               default: 
                     break; 
            } 
         } 
   } 
   return flatImage; 
} 

Add the Save Reversed Image Code

Navigate back to the form's Designer, using the Solution Explorer. Add a new &Save Reversed MenuItem to the File dropdown menu. Leave the new item's name as saveReversedToolStripMenuItem.

Double-click the &Save Reversed menu item to create its event handler, then add the following code in it to export the animated GIF.

C#
private void SaveReversedToolStripMenuItem_Click(object sender, EventArgs e) 
{ 
   if (_reversedImage == null) 
   { 
         MessageBox.Show("Unable to save! Please load an image first"); 
         return; 
   } 
   try 
   { 
         SaveFileDialog saveDlg = new SaveFileDialog(); 
         saveDlg.Filter = "GIF image|*.gif"; 
         if (saveDlg.ShowDialog(this) != DialogResult.OK) 
            return; 
         using RasterCodecs codecs = new RasterCodecs(); 
         codecs.Save(_pictureBox.Image, saveDlg.FileName, RasterImageFormat.Gif, 8); 
   } 
   catch (Exception ex) 
   { 
         MessageBox.Show(ex.ToString()); 
   } 
} 

Add the Animation Playback Code

Open Form1.cs in the Solution Explorer. Add a new dropdown menu, Animation, next to the File dropdown menu. Add the following three MenuItems to the new dropdown menu:

Item Text Item Name
Play &Forward playForwardToolStripMenuItem
Play &Reversed playReversedToolStripMenuItem
&Stop stopToolStripMenuItem

Double-click each of the three new items to add event handlers for them, and implement them as follows:

C#
private void PlayForwardToolStripMenuItem_Click(object sender, EventArgs e) 
{ 
   if(_forwardImage == null) 
   { 
      MessageBox.Show("Unable to play animation! Please load an image first"); 
      return; 
   } 
   _pictureBox.Image = _forwardImage; 
   _pictureBox.AnimationMode = RasterPictureBoxAnimationMode.Infinite; 
   _pictureBox.PlayAnimation(); 
} 
C#
private void PlayReversedToolStripMenuItem_Click(object sender, EventArgs e) 
{ 
   if (_reversedImage == null) 
   { 
      MessageBox.Show("Unable to play animation! Please load an image first"); 
      return; 
   } 
   _pictureBox.Image = _reversedImage; 
   _pictureBox.AnimationMode = RasterPictureBoxAnimationMode.Infinite; 
   _pictureBox.PlayAnimation(); 
} 
C#
private void StopToolStripMenuItem_Click(object sender, EventArgs e) 
{ 
   _pictureBox.StopAnimation(); 
} 

Run the Project

Run the project by pressing F5, or by selecting Debug -> Start Debugging.

If the steps were followed correctly, the application runs and loads any multipage image selected by the user, ensures it is animated, and creates a backward-animated copy of the image. It also allows saving the reverse-animated image to a new GIF file, and playing both forward and reversed animations.

Screenshot of GIF loaded.

Wrap-up

This tutorial showed how to add the necessary references to load, reverse, playback, and save animated images. In addition, it showed how to use the RasterPictureBox and RasterImageAnimator classes.

See Also

Help Version 23.0.2024.5.22
Products | Support | Contact Us | Intellectual Property Notices
© 1991-2024 LEAD Technologies, Inc. All Rights Reserved.

Products | Support | Contact Us | Intellectual Property Notices
© 1991-2023 LEAD Technologies, Inc. All Rights Reserved.