Build a Generative Art Application With Pillow, Flask and HTMx
Last updated
Was this helpful?
Last updated
Was this helpful?
Python’s Pillow package provides support for image manipulation that we can leverage to create random graphic images.
In this tutorial, we’ll show you how to build a web application that creates images with rectangle graphics of different colors and sizes, and makes them available for download when requested by a user.
Here’s an example of a graphic image that can be created by the app we’ll build:
You can also add text to the generated images to create image covers and different marketing posts.
You will need the following to complete the tutorial and host your application on Code Capsules:
IDE or text editor of your choice
Python 3 installed
To begin, we need to create a project folder to house all our files.
In a terminal, navigate to the directory you’ll be keeping the application files in. Run the commands below to create the project folder and navigate into it.
Copy
Next, we’ll create a virtual environment, which will allow us to isolate the packages we need to run our application from the computer system. Run the command below from a terminal in the project root folder to create a virtual environment called env
:
Copy
To activate the virtual environment, run one of the following commands, depending on your OS:
MacOS
Copy
Windows
Copy
When you’ve activated the virtual environment, the name env
will appear on the far left of your current line. This confirms that the activation was successful.
Now we can install dependencies our app needs to the environment. Run the command below from a terminal in the project root folder to install the packages we’ll need:
Copy
Let’s initialize a Git repository so that we can make use of version control throughout the course of this tutorial and keep track of our changes. Run the command git init
to create a new empty repository in the project root folder.
The final setup step is to link to GitHub. We’ll link our newly created local git
repository to a remote one that we can deploy to Code Capsules from. The remote repository can be thought of as a mirror image of the local one, and we’ll update the remote repository when new code works as expected locally.
Copy
We can now start building our generative art app, and we’ll start with the frontend using Flask templates. Create an app/templates
folder inside the project root folder and add a file named home.html
to it. This file will contain the code for the landing page of our app. Populate it with the code below:
Copy
The <link>
tag in the <head>
section links to Bootstrap to simplify styling for common HTML elements like forms and buttons, while the <style>
tag adds any extra unique styling and responsiveness we might need.
The <meta>
tag in the <head>
section provides the relevant metadata required to allow our @media
queries to give our app responsiveness, making it readable on both large and smaller screens.
We’ll be using HTMx to send requests to generate a new graphic image, and we include it in the project by adding the <script>
tag below the <link>
tag. HTMx makes it possible to add interactivity to traditional multipage HTML sites without any of the extra complexity that’s introduced by popular single-page frameworks.
Next, we’ll add the code for the body of the home page. Copy and paste the snippet below underneath the closing </head>
tag in home.html
:
Copy
Our app has two main features: it allows a user to generate new graphic images and to download them. The “I hate this art, make me another” button sends a request to the /generate-another
route, which handles the creation of a new graphic image. When the app generates an image a user likes, the user can download that image by pressing the “Download” button. This download button has access to the newly created graphic image.
The <img>
tag below the page header takes in a Base64 string as input and renders the corresponding graphic image to the screen. The download button also accesses this Base64 string to allow for the download of the image. We’ve assigned an id
value of "image-update-div"
to the div that contains both this image and the download button to allow us to use HTMx to update the image when a user clicks the “I hate this art, make me another” button. You’ll notice three HTMx attributes in the button’s src
code, which is located at the bottom of the page. Let’s go over them and see what each one is responsible for:
hx-target
: This attribute accepts an id
value prefixed by a #
. It lets HTMx know which element to swap on a successful request.
hx-get
: The hx-get
attribute sends a GET
request to the specified URL. If we wanted to send a POST
request, we would have used the hx-post
attribute instead.
hx-swap
: This attribute tells HTMx how to swap out the old with the new elements after a successful request. In our case, we’ve used the value of "outerHTML"
to specify that the entire <div>
element be replaced by the response. Other accepted values include but are not limited to innerHTML
, beforeend
, and afterend
.
The backend contains the interesting bits of our app’s logic. Here, we will see the logic for the two routes that are called in the frontend.
Create a file named run.py
in the project root folder and populate it with the code below:
Copy
The code above is responsible for starting our application by calling Flask’s run
method.
app
ModuleLet’s go ahead and initialize the app
module we imported in the previous code snippet. Create an __init__.py
file inside the /app
folder and populate it with the code below:
Copy
In the code above, we create a Flask app
object and import the app views we’ll add later on.
Next, let’s create the file that will make use of the palettes we defined. In the /app
folder, add a file named make_squares.py
and populate it with the code below:
Copy
The module defined in the code snippet above leverages the Pillow package to create new random images using the palettes we defined in the palettes.json
file. In lines 10-15, we open the palettes.json
file and add its contents to a local array named palettes
that we’ll use in the create()
method.
The create()
method is responsible for generating Base64 image strings for new random images. It does so by first creating a blank canvas and adding a random number of rectangles of different sizes and colors. When the image has been created, it’s returned as a Base64 image string, which is more efficient to transfer between our app modules.
The last step in building our backend is to add the application views. To achieve this, create a file named views.py
inside the /app
folder and populate it with the code below:
Copy
At the top of the file, we import the create
method from the make_squares
module, since our views need to return the Base64 image string when responding.
The index
route is called when the app is started, and it calls the create()
method to generate a Base64 image string and returns it in the home.html
template. The /generate-another
route is called when a user clicks on the “I hate this art, make me another” button. It saves the new graphic image to the /tmp
folder before returning it as part of an HTML response, since the request is triggered by HTMx. This allows our app to only refresh the image element, and download reference, and not the whole page, like in the case of rendering templates.
Our generate art app is now complete, and we are only left with adding the files necessary for deployment before we can publish it.
requirements.txt
We’ll start by creating a Procfile, which tells Code Capsules how to run our app. Create a file named Procfile
in the project root folder and add the following code to it:
Copy
We use the gunicorn
server to run our app in production, since the built-in Flask server is less secure and only suitable to be used in a development environment.
Next, we need to generate a requirements.txt
file to tell Code Capsules which packages need to be installed first before our app can start. Run the command below from a terminal while in the project’s root folder to create a requirements.txt
file.
Copy
.gitignore
Before we push our local changes to the remote repository, we must stop tracking our virtual environment folder. Create a file named .gitignore
in the project root folder and add the code below to it:
Copy
Let’s add and commit all the files we created to our local repository and then push them to the remote one. Do this by running the commands listed below in a terminal while in the project’s root folder:
Copy
Your remote repository will now be up-to-date with your local one.
That’s it! Your “Generate Art” app should be live and fully functional now.
A account
Git set up and installed, and a registered account
Head over to and create a new repository. You’ll be presented with instructions for linking your new remote repository to a local one. Go back to your terminal in the project root folder and run the command below, taking care to replace the username
and repository_name
with your own values.
You can view other HTMx attributes and their functionalities .
The next step is to add logic for the graphic image generation. Create a file named palettes.json
in the project root folder and populate it with the code in this . This is a list of 2D arrays containing random numbers that represent different color palettes. We sourced these color palettes from . Our app will pick randomly from these each time a user chooses to generate a new image.
The final step is to deploy our app. Log into your Code Capsules account and link your remote GitHub repository to Code Capsules. Create a Backend Capsule and deploy the app there. You can follow this to see how to do this in greater detail.