Using .NET and PowerPoint to generate cover images

  • Gérald Barré

If you follow me on Twitter, you may have noticed that I use a cover image for the posts. This improves the visibility of the posts I write on people's timelines.

The image is composed of 3 parts:

  • The post categories
  • The post title
  • The author website and Twitter handle

Of course, I do not want to create all these images manually. Also generating an image with a dynamic text is not that trivial. For instance, the title length is variable. This means you need to wrap the text and adjust the text size to fit the available size. Sometimes it fits on one line, sometimes it needs 3 lines, and sometimes it needs to reduce the font size. Last but not least, creating the image template is not simple.

The solution I chose is to use a PowerPoint slide with editable text areas. PowerPoint allows to easily creates the template. You can add a background image, change the font size and color. The more important is that you can see the result immediately. Also, PowerPoint automatically resizes the text to fit the area. So, whatever the title length it will fit the area.

You can automate PowerPoint using COM but this doesn't work on Linux and requires PowerPoint to be installed on the machine. I generate this static web site on GitHub actions using a Linux Docker image, so COM is not an option. Instead, I use Syncfusion to edit the PowerPoint slide and export it as a PNG image. Syncfusion has a free community license for companies and individuals with less than $1 million USD in annual gross revenue and 5 or fewer developers. This is perfect for a personal website as this one.

First, you need to create the template. The editable areas are named, so it is easy to find them from the code. Note that the slide must have the right size to be used as a Twitter card. Check the Twitter documentation for more information about the image size and the PowerPoint documentation to change the size of your slides.

Then, add the following NuGet packages to your project:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <ItemGroup>
    <PackageReference Include="Syncfusion.Presentation.Net.Core" Version="18.2.0.48" />
    <PackageReference Include="Syncfusion.PresentationRenderer.Net.Core" Version="18.2.0.48" />
  </ItemGroup>

</Project>

Then, you just need a few lines of code to edit the slide and convert it to a PNG image.

using Syncfusion.Presentation;
using Syncfusion.PresentationRenderer;

public static async Task Generate(string templatePath, string category, string title, string destinationImagePath)
{
    // Get your license from the syncfusion website
    Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense("...");

    // You can validate the license is valid using the following method.
    // This is common to forget to update the license when updating the syncfusion NuGet packages.
    // Note that when the license is not valid, Syncfusion adds a watermark.
    if (!Syncfusion.Licensing.SyncfusionLicenseProvider.ValidateLicense(Syncfusion.Licensing.Platform.FileFormats, out var message))
        throw new Exception("Syncfusion license is invalid: " + message);

    // Load the PowerPoint file
    using var pptx = Presentation.Open(templatePath);
    pptx.PresentationRenderer = new PresentationRenderer();
    pptx.PresentationRenderer.ExportChartImageOptions.ScalingMode = Syncfusion.OfficeChart.ScalingMode.Best;

    // Edit the category and title areas
    var slide = pptx.Slides[0];
    foreach (var shape in slide.Shapes.OfType<IShape>())
    {
        if (shape.ShapeName == "ItemCategory")
        {
            shape.TextBody.Text = category;
        }
        else if (shape.ShapeName == "ItemTitle")
        {
            shape.TextBody.Text = title;
        }
    }

    // Export the slide to a png image

    // When generating many images in parallel, Syncfusion sometimes fails to write directly to the file.
    // Using an intermediate MemoryStream seems to prevent the error.
    using var pngStream = slide.ConvertToImage(ExportImageFormat.Png);
    using var ms = new MemoryStream();
    await pngStream.CopyToAsync(ms);

    await File.WriteAllBytesAsync(destinationImagePath, ms.ToArray());
}

Note that PowerPoint and Syncfusion behaviors may differ. If some things are not rendered correctly, feel free to report bugs to Syncfusion.

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee