Courses/Streamlit: 20 Real Apps/Module 3: Beginner Projects
Module 3 · Lesson 820 minBeginner

Project 8: QR Code Generator

What you'll build
Build a themed QR generator with instant PNG download.

Introduction

QR codes are everywhere — from scanning menus to making payments or sharing links. In this tutorial, you will learn how to build a fully functional QR Code Generator web app using Python, Streamlit, and the qrcode library. QR codes pair naturally with image handling — see the Pillow image processing tutorial for the deeper dive.

We will also add options for customization, allowing users to pick custom background and fill colors, adjust the sizing, and download the generated QR code as a PNG file.


> 🎬 Watch the Full Video Tutorial:

> Learn the concepts step-by-step on YouTube: Python PRO Shares Top QR Code Generator Techniques


Prerequisites

Before starting, install the required packages using pip:

bash
pip install streamlit qrcode pillow

Step 1: Create the App Script

Create a new file named qr_generator.py and add the following Python code:

python
import streamlit as st
import qrcode
from PIL import Image
import io

st.set_page_config(page_title="QR Code Generator", page_icon="📷", layout="centered")
st.title("📷 Custom QR Code Generator")

# User Inputs
st.subheader("🔧 Configure Your QR Code")
data = st.text_input("Enter the text or URL for your QR Code:", "https://techwithgalvan.in")

col1, col2 = st.columns(2)
with col1:
    fill_color = st.color_picker("Fill Color (QR Pattern)", "#000000")
with col2:
    back_color = st.color_picker("Background Color", "#ffffff")

box_size = st.slider("Box Size (Resolution)", min_value=5, max_value=20, value=10)
border = st.slider("Border Thickness", min_value=1, max_value=10, value=4)

if st.button("⚡ Generate QR Code"):
    if data:
        # Generate QR Code
        qr = qrcode.QRCode(
            version=1,
            error_correction=qrcode.constants.ERROR_CORRECT_L,
            box_size=box_size,
            border=border,
        )
        qr.add_data(data)
        qr.make(fit=True)

        # Create Image
        img = qr.make_image(fill_color=fill_color, back_color=back_color)
        
        # Convert image to bytes for display and download
        buf = io.BytesIO()
        img.save(buf, format="PNG")
        byte_im = buf.getvalue()

        # Display QR Code
        st.image(byte_im, caption="Your Generated QR Code", use_container_width=False)
        
        # Download Button
        st.download_button(
            label="💾 Download QR Code (PNG)",
            data=byte_im,
            file_name="qrcode.png",
            mime="image/png"
        )
    else:
        st.warning("Please enter some text or a valid URL!")

Step 2: Run the Application

Launch your local Streamlit app by executing:

bash
streamlit run qr_generator.py

How It Works

The qrcode library encodes text into a QR matrix and hands it to Pillow for rendering. The QRCode class takes three meaningful parameters: version (size, or None to auto-fit), error_correction (how much damage a code can survive — ERROR_CORRECT_H survives ~30% damage but stores less data), and box_size (pixel width of each module).

Making the QR auto-size by leaving version as None is the pragmatic choice: the library picks the smallest version that fits your text. The fill/back colors accept any RGB tuple, which is how the app offers custom theming — though high contrast matters more than style, since scanners need the dark modules distinguishable.

The download flow is a pattern worth memorizing: save the PIL image to an in-memory BytesIO buffer, then pass those bytes to st.download_button — no temp files, no filesystem cleanup. The same buffer pattern works in the image uploader app.

Key Concepts Covered

* `qrcode.QRCode()` — Configuration object for determining layout settings (borders, size, error correction level).

* `st.color_picker()` — Allows selecting hex colors through native browser picker.

* `st.download_button()` — Facilitates direct downloads of in-memory files (like bytes objects).

What to Try Next

* Logo Overlay: Learn how to embed a custom image/logo right in the center of the QR code using PIL.

* Dynamic URLs: Generate QR codes dynamically based on user databases.

Common Errors & Fixes

  • DataTooLongException — QR versions max out around 2,953 bytes. For URLs, shorten first; for payloads like vCards, use ERROR_CORRECT_L to squeeze in more data.
  • Generated QR won't scan — usually contrast: light-gray-on-white fails. Keep dark modules genuinely dark and test with two different phone scanners.
  • `ModuleNotFoundError: PIL` — qrcode renders via Pillow; pip install qrcode[pil] installs both.
  • Download button saves a corrupt file — you passed the PIL object directly; convert to bytes with the BytesIO buffer first.
  • FAQ

    Do QR codes expire?

    No — a QR code is just an encoding of your text. It 'expires' only if the URL it points to dies.

    What error correction level should I use?

    Level M (default, ~15% recovery) suits screens. Use H for print stickers that might get scratched or partially covered.

    Can I add a logo to the center?

    Yes — paste a resized logo onto the QR with Pillow at level H error correction, keeping the logo under ~20% of the code area. The compositing steps are in the Pillow tutorial.

    Adapted from: QR Code Generator using Python and Streamlit

    Checkpoint
    The downloaded QR scans correctly with your phone camera.
    What you learned
    • The qrcode library and error correction levels
    • BytesIO in-memory export
    • st.download_button