Automatically create 100s of icons

The power of information and automation comes in all shapes and sizes, from something very trivial like summing to integers in a group, to automating construction management workflows for billion dollar projects. In this wide spectrum of use cases, the essence is generally saving time and money.

In this blog post, I'm going to demonstrate how to use Python to create icons using the names of tables. Alright, you might be thinking, how long would it take to create a logo of a table. Not a lot right? How about if you had a project with 100, 200, or 500 tables. Would you be willing to create all the images manually? If the answer is yes, you have the patience of a saint! If you're like us common mortals, the below might save you some time.

⚠️ Caution: basic Python skills needed


Step 1: Create an Image from text Using Python

Yes! You can create a basic image from a text in Python. To do that we need the Pillow python library. This library has ready-made functions that can create images according to your needs. For example, something like this:


So the first step is to create a function that will create a simple image that has a blue background and white text. The optimal width and height for a logo on Morta are 230 x 200. You can also specify a font, size and wrap text in case its longer than the image's width.


Step 2: Update a table's logo based on its name

After customizing the way you create your logo, you will need to create another function which updates the tables logo based on its name. To do that we'll use the requests python library which handles API requests in python.

Step 3: Loop over all Tables

The final step is to loop over the tables in your Morta project and update their logos one at a time.

Full Code

import io
from PIL import Image, ImageDraw, ImageFont
import textwrap
import mimetypes
import requests

URL = ""
# MORTA_USER_TOKEN is your morta token which can be created from your Morta profile

def main():
    # fill in your project id below
    project_id = ""

def create_logo(text: str) -> Image:
    # initialize variables
    image_width = 230
    image_height = 200
    font_size = 30
    font = "calibri.ttf"
    color_mode = "RGB"
    color_definition = (43, 51, 137)
    max_line_length = 16
    fill_color = "#FFFFFF"
    anchor = "mm"
    alignment = "center"

    # create the image
    image =, size=(image_width, image_height), color=color_definition)

    # create the canvas
    canvas = ImageDraw.Draw(image)
    font = ImageFont.truetype(font=font, size=font_size)

    # wrap text
    new_lines = []
    lines = text.split("\n")

    for line in lines:
        if len(line) > max_line_length:
            w = textwrap.TextWrapper(width=max_line_length, break_long_words=False)
            line = "\n".join(w.wrap(line))


    new_text = "\n".join(new_lines)

    # add text to canvas
        xy=((image_width) / 2, (image_height) / 2),

    return image

def update_table_logo(table_id: str, table_name: str):
    # create the new logo
    new_logo: Image = create_logo(text=table_name)

    # upload logo to Morta and get URL
    file_name = f"{table_name}.png"
    file_type = mimetypes.guess_type(file_name)[0]
    buffer = io.BytesIO(), format="PNG")
    image_file = buffer.getvalue()

    file_tuple = (file_name, image_file, file_type)

    uploaded_file = upload_file(file=file_tuple)
    new_logo_url = uploaded_file["url"]

    # update the table
    update_table(table_id=table_id, params={"logo": new_logo_url})

def upload_file(file: tuple) -> dict:
    headers = {"Authorization": f"Bearer {MORTA_USER_TOKEN}"}
    files = {"file": file}
    endpoint = "/v1/files"
    destination_url = f"{URL}{endpoint}"
    response =, files=files, headers=headers)

    return response.json()["data"]

def update_table(table_id: str, params: dict) -> dict:
    headers = {"Accept": "application/json", "Authorization": f"Bearer {MORTA_USER_TOKEN}"}
    endpoint = "/v1/table/"
    destination_url = f"{URL}{endpoint}{table_id}"
    response = requests.put(url=destination_url, headers=headers, json=params)

    return response.json()["data"]

def loop_and_update(project_id: str):
    tables = get_tables(project_id=project_id)
    for table in tables:
        update_table_logo(table_id=table["publicId"], table_name=table["name"])

def get_tables(project_id: str) -> list:
    headers = {"Accept": "application/json", "Authorization": f"Bearer {MORTA_USER_TOKEN}"}
    endpoint = f"/v1/project/{project_id}/tables"
    destination_url = f"{URL}{endpoint}"
    response = requests.get(url=destination_url, headers=headers)

    return response.json()["data"]

if __name__ == "__main__":



As a final note, I suggest you debug your way through this code and save the image on your machine to check it before updating all your tables on the project.

Happy coding!

Leave a Comment