Creating my own image generation API with Flask and Pillow

TLDR: I wanted to make my own version of Bannerbear, so I created a very basic Python app. It uses the Pillow library to generate the PNG images and the Flask library to serve the API. It mostly worked! It was fun. Would recommend as a weekend project.

Skip the preamble and go straight to the How it works section.

Sometimes you see someone’s SaaS product and you get really jealous. Wicked jealous, in fact. The product is great, the marketing is superb, the story is exciting, the money is apparent, and the success of it all is so aluring.

This happened to me recently when I rediscovered a product that I’d found on Hacker News about a year ago: Bannerbear, which is a SaaS product that allows you to use web API calls to generate banner images that can be quickly and programatically used in social media posts, website content, and any other text-and-logo-on-a-nice-background-as-a-PNG-file use case.

Now, I haven’t actually tried it out yet, but if the functionality matches the landing page sales pitch then, honestly…it’s really cool.

I’d recently found myself in need of something like this – the company I co-own, Arc Analytics, is starting our first serious marketing effort soon, for which we’ll be creating blog posts, videos, LinkedIn posts, and we may exlore using other social media options as well.

For all of our content, we’ll need banner and thumbnail images to make our content stand out and have more of a consistent feel. I didn’t like the idea of having to manually create all of these images myself every time we had new content to put out, especially if I wanted to ensure consistency. I also could have just paid for Bannerbear (and I still might), but free is also great and I think it’s something I can solve myself. Since our team is small, anything laborious or costly that I can otherwise automate, I will.

So, I did! Nothing near as robust as Bannerbear, it’s really more of a proof of concept to see how it could work. I created this small program using Python, specifically using the Pillow library to generate the images and serving it up with Flask. There are just two REST endpoints for the app: /new and /test:

Now let’s see how all the pieces fit together.

How it works

We have code that generates the image and then code that serves the API. Here’s all of the code, which can be interacted with through Replit:

Let’s first look at how we actually generate the images given user-provided text.

Image generation functions

We start this off by looking at our image_functions.py file, which has all of our image-manipulation code and helper functions.

Here are the functions used:

Going further in the generate_image() function, here are the steps to generating our PNG file:

API serving functions

Now let’s look at how we’re serving up the application. Flask is my go-to for this since it’s mature and easy to use. The Flask code is in our app.py file.

Here are the routes I created for this project:

How it could work better

This project was always meant to only be a little project, the goal of it being to improve my skills with Flask, Pillow, and Python in general. Because of this, it lacks a ton of features that would normally be important for an application like Bannerbear. It lacks strong security, more complete Image generation features like logo placement or different base image options, different font options, etc.

The most glaring thing it’s missing, in my opinion, is the lack of temporary image clean-up – as it stands, those images and their “temporary folders” aren’t temporary at at all! I had initially planned on adding a “automatically delete temp folders and their contents after 5 minutes” component as a way to learn how to use the Celery library, but I just never did that part 🤷‍♂️. If I were to revisit this project, that’d be the first thing I’d add.

Takeaways

This project was:

I hope to revisit this project at some point, as there are a ton of ways I can make it better and more useable!