How to Easily Build Customizable QR Codes with Python

How to Easily Build Customizable QR Codes with Python

QR codes are everywhere. From restaurant menus to product packaging, they’ve become a popular way to share information. You can use them to link to websites, share contact details, or even direct people to an app.

I recently had to work a project that would generate QR codes with Python. The idea was for a banner that had a quick response code that led directly to a CashApp account. (Yes, I am aware that CashApp has QR codes readily available for users but this script was written to use for other sites as needed.) This was to be used by performers, like musicians, to display and have venue patrons send them tips.

When I have to do something in particular like this, I try to think of ways to make a systematic way of doing things. In this case, I wanted to have something I could use again if another band wanted a QR code. I will get into my approach, but first I want to make sure we are on the same page about quick response codes.

If you want to skip out on the explanation of the code and the process, you can find the code on GitHub.

What Are QR Codes?

QR codes (Quick Response codes) are two-dimensional barcodes that store data, like a website URL or text. Unlike regular barcodes, QR codes can hold much more information and are readable by most smartphones.

You’ve probably seen QR codes used to:

  • Link to websites or apps

  • Share contact information

  • Display menus in restaurants

  • Track inventory in businesses

QR codes are made up of tiny squares (called modules) arranged in a grid. The code is scanned using a QR code reader, and it translates the grid into the information stored inside. The more data you store, the larger and more complex the grid becomes.

Why Customize QR Codes?

While standard black-and-white QR codes work just fine, they don’t always look good on every design. And since all bands have different styles, customizing the color of the QR code can make it look better and help it stand out.

Custom QR codes can:

  • Match your brand colors

  • Blend in with your design

  • Be more visually appealing

By adding a bit of color, your QR codes become more than just functional, they become part of your brand.

Tools and Libraries Needed for this Project

Before we start coding, you’ll need a few tools. Python has libraries that make generating QR codes and customizing their appearance easy. We’ll use two main libraries:

  1. qrcode: This library generates the QR code itself.

  2. Pillow (PIL): This is a library for handling images in Python, and it will help us manage colors.

You can install these libraries by running this command in your terminal:

pip install qrcode[pil]

Once the libraries are installed, you’re ready to start creating QR codes.

Understanding the Basics of QR Codes

A QR code is a matrix of tiny black and white squares. Each square represents a bit of data. The more squares, the more data can be stored in the code. However, larger QR codes can be harder to scan. That’s why it’s important to balance the size of your QR code with the amount of data you want to store.

QR codes also have error correction built into them. This means that even if part of the code gets damaged (say, scratched or dirtied), it can still be scanned and understood by a QR reader.

There are four levels of error correction: L (low), M (medium), Q (quartile), and H (high). Each level allows for a different percentage of the QR code to be restored if it’s damaged.

Level L: 7% of data can be restored.

Level M: 15% of data can be restored.

Level Q: 25% of data can be restored.

Level H: 30% of data can be restored.

In this tutorial, we’ll use error correction level L, which allows for about 7% of the QR code to be restored.

Step 1: Creating a Simple QR Code

Let’s start by generating a basic QR code. First, create a Python file (for example, qr_code_generator.py) and add this code:

import qrcode

def create_qr_code(data, filename):
    qr = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_L,
        box_size=10,
        border=4,
    )

    qr.add_data(data)
    qr.make(fit=True)

    img = qr.make_image(fill_color='black', back_color='white')
    img.save(f"{filename}.jpg")

website_url = input("Enter the URL you want to encode into the QR code: ")
filename = input("Enter the name for the QR code file (without extension): ")

create_qr_code(website_url, filename)

In this code:

  • version=1: Controls the size of the QR code. Version 1 is the smallest.

  • error_correction: We use level L, which can restore 7% of the data if the QR code is damaged.

  • box_size: This sets the size of each square in the QR code grid.

  • border: This is the white border around the QR code, which ensures it’s scannable.

When you run this script, it will ask for a URL and a file name. It will generate a QR code and save it as a .jpg file. This is all I really needed to do for my project, but this is a standard black-and-white QR code. I wanted to take it up a notch and add some colors.

Step 2: Adding Custom Colors to QR Code

Customizing the colors of your QR code is a great way to make it fit your brand. You can change the color of the QR code itself (the black squares) and the background which is usually white.

We can accept color input from the user in two formats:

  1. Hex codes: Commonly used in web design (e.g., #000000 for black).

  2. RGB tuples: Represents color values as three numbers (e.g., (0, 0, 0) for black).

First, we need a function to parse the colors:

from PIL import ImageColor

def parse_color(color_input, default_color):
    try:
        if color_input.startswith('#'):
            return ImageColor.getrgb(color_input)
        else:
            return eval(color_input)
    except:
        print(f"Invalid color format. Using default color ({'black' if default_color == (0, 0, 0) else 'white'}).")
        return default_color

This function checks if the color is in hex or RGB format. If it’s invalid, it defaults to black for the qr code and white for the background. The options of what you can do here as far as color selection are pretty endless.

You may have noticed that if a user enters a hex code, the function will return the color in RGB. The reason we convert hex codes to RGB using ImageColor.getrgb() is that the library (Pillow and qrcode) works with RGB color values when creating images. While hex color codes are convenient and widely used in web development and design, most image manipulation libraries in Python, including Pillow, require colors in the RGB format.

Step 3: Full Script with Color Customization

Now let’s modify the script to allow the user to customize the QR code and background colors:

import qrcode
from PIL import ImageColor

#Function to parse color input, with a specified default color if input is invalid
def parse_color(color_input, default_color):
    try:
        #If the input is a hex color, convert it to an RGB tuple
        if color_input.startswith('#'):
            return ImageColor.getrgb(color_input)
        #If the input is an RGB tuple (e.g., "(255, 255, 255)"), evaluate it
        else:
            return eval(color_input)
    except:
        #If the input is invalid, print a message and return the default color
        print(f"Invalid color format. Using default color ({'black' if default_color == (0, 0, 0) else 'white'}).")
        return default_color  

#Function to create a QR code with customizable colors and save it as a JPG file
def create_qr_code(data, filename, fill_color, back_color):
    #Create a QRCode object with specified parameters
    qr = qrcode.QRCode(
        version=1,  
        error_correction=qrcode.constants.ERROR_CORRECT_L,  
        box_size=10,  
        border=4, 
    ) 

    #Add the data (e.g., URL) to the QR code
    qr.add_data(data)
    qr.make(fit=True)  #Fit the QR code to the data provided

    #Parse the fill and background colors, defaulting to black for fill and white for background
    fill = parse_color(fill_color, (0, 0, 0))  # Default to black if fill_color is invalid
    background = parse_color(back_color, (255, 255, 255))  # Default to white if back_color is invalid

    #Create an image of the QR code with the specified fill and background colors
    img = qr.make_image(fill_color=fill, back_color=background)

    #Convert the image to RGB mode to ensure it can be saved as a JPG
    img = img.convert("RGB")

    #Save the image as a JPG file
    img.save(f"{filename}.jpg")
    print(f"QR code saved as {filename}.jpg with QR color {fill_color} and background color {back_color}.")

#Get inputs from the user
website_url = input("Enter the website URL you want to encode into the QR code: ")
filename = input("Enter the name for the QR code file (without extension): ")
fill_color = input("Enter the QR code color (hex or RGB): ")
back_color = input("Enter the background color (hex or RGB): ")

#Generate and save the QR code with custom colors
create_qr_code(website_url, filename, fill_color, back_color)

In this script:

  • The user can now input both the color of the QR code and the background.

  • We use the parse_color function to handle different color formats.

  • The QR code is saved with the custom colors as a .jpg file.


Step 4: Running the Script

To run the script:

  1. Open a terminal or command prompt.

  2. Navigate to the folder where you saved the script.

  3. Run the script using:

python qr_code_generator.py

The program will ask for:

  • The URL you want to encode.

  • The name of the file.

  • The color of the QR code (in hex or RGB).

  • The background color (in hex or RGB).

After providing the inputs, the script will generate a QR code and save it as a .jpg file with the colors you chose.

Here are two example QR codes created:

Error Handling and Best Practices

It’s important to make sure your QR code stays readable after customizing it. Avoid using colors that are too similar (like light blue on a white background) because it can make the code hard to scan.

To make sure the QR code is always readable, our script includes error handling:

  • If the user enters an invalid color for the QR code, the script defaults to black.

  • If the user enters an invalid color for the background, the script defaults to white.

  • This prevents crashes and ensures the QR code is always scannable.


Customization Ideas

Now that you’ve learned the basics, there are many ways to expand this project:

  1. Adding a Logo: You can overlay a logo in the center of the QR code to make it more personalized.

  2. Adjusting the Size: You can change the version parameter to make the QR code bigger or smaller.

  3. Creating Dynamic QR Codes: These can change the destination (URL) without needing to regenerate the QR code.

Hope that you found this helpful!