Creating a gif from images using ImageSharp

There are several techniques one can use to create a gif on Windows. You can use FFMPEG. Or you can use Six Labors ImageSharp.

In the following I present to you my solution using ImageSharp:

// Images that will be included in the gif. The duration is in milliseconds
List<(string path, int duration)> images = new List<(string, int)>()
{
    //100 => 1 second
    ("image1.jpg", 100),
    ("image2.jpg", 150)
};

// The final dimensions of the gif
int width = 500, height = 500;

// Create a blank canvas for the gif
using (var gif = new Image<Rgba32>(width, height))
{
    for (int i = 0; i < images.Count; i++)
    {
        // Load image that will be added
        using (var image = Image.Load(images[i].path))
        {
            // Resize the image to the output dimensions
            image.Mutate(ctx => ctx.Resize(width, height));

            // Set the duration of the image
            image.Frames.RootFrame.Metadata.FrameDelay = images[i].duration;

            // Add the image to the gif
            gif.Frames.InsertFrame(i, image.Frames.RootFrame);
        }
    }

    // Save an encode the gif
    using (var fileStream = new FileStream("result.gif"))
    {
        gif.SaveAsGif(fileStream);
    }
}

You can further optimize the process when you perform the resizing in parallel. We dont want to delete the original images, so a temp directory for the resized images is necessary.

async Task CreateGif(List<(string, path, int duration)> images,
                      string resultFilePath = "result.gif",
                      int width = 500,
                      int height = 500,
                      string tempPath = "/temp")
{
    // Iterate in parallel over the images and wait until all images are processed
    await Parallel.ForEach(images, (data, state, index) =>
    {
        // Exit when an error occurred or the foreach has stopped
        if (state.ShouldExitCurrentIteration || state.IsExceptional || state.IsStopped)
        {
            return;
        }

        // Load the image
        using (var image = Image.Load(data.path))
        {
            // Resize the image
            image.Mutate(ctx => ctx.Resize(width, height));

            // Build temp path for image based on index
            string resizeTempPath = Path.Combine(temPath, $"{index}.{Path.GetExtension(path)}");

            // Save the image
            image.Save(resizeTempPath);
        }
    });
    
    // Iterate over the images to create the gif
    for (int index = 0; index < images.Count; i++)
    {
        // Build path to resized image
        string resizeTempPath = Path.Combine(temPath, $"{index}.{Path.GetExtension(images[index].path)}");

        // Load the resized image that will be added
        using (var image = Image.Load(resizeTempPath))
        {
            // Set the duration of the image
            image.Frames.RootFrame.Metadata.FrameDelay = images[index].duration;

            // Add the image to the gif
            gif.Frames.InsertFrame(index, image.Frames.RootFrame);
        }
    }
}

    // Save an encode the gif
    using (var fileStream = new FileStream(resultFilePath))
    {
        gif.SaveAsGif(fileStream);
    }

    // Cleanup temp directory with content
    Directory.Delete(temPath, true);
}

Happy coding!

Niels Morf}

Niels Morf

Developer, Larper, Sailor, Human

Comments

Loading...

New Comment

When clicking "Post" you agree to publish your comment publicly and have acknowledged the privacy implications below.



Privacy: The following information will be stored when you post a comment:

  • Name (Visible to others)
  • E-Mail (Visible as md5 hash only when using the gravatar option)
  • Your IP-Adress
  • Date and time of your comment (Visible to others)
  • The content of your comment (Visible to others)
Your e-mail address may be used to contact you in response to your comment. Otherwise the data will only be used to display the comments.