Python QR Code Generation — Core Concepts

What the qrcode library does

The qrcode library generates QR code images from arbitrary text or data in Python. It handles encoding, error correction, and rendering — you provide data, it returns an image you can save, display, or embed.

Install with pip install "qrcode[pil]" to include Pillow for image output.

Quick generation

The simplest path from data to image:

import qrcode

img = qrcode.make("https://example.com")
img.save("example_qr.png")

qrcode.make() returns a Pillow Image object. For more control, use the QRCode class.

The QRCode class

import qrcode

qr = qrcode.QRCode(
    version=1,
    error_correction=qrcode.constants.ERROR_CORRECT_M,
    box_size=10,
    border=4,
)
qr.add_data("https://example.com/long-path?param=value")
qr.make(fit=True)

img = qr.make_image(fill_color="black", back_color="white")
img.save("custom_qr.png")

Key parameters:

  • version — integer from 1 to 40, controlling the grid size. Version 1 is 21×21 modules; each increment adds 4 modules per side. Version 40 is 177×177. Set to None or use fit=True to auto-select.
  • error_correction — how much damage the code can survive:
    • ERROR_CORRECT_L — ~7% recovery
    • ERROR_CORRECT_M — ~15% recovery (default)
    • ERROR_CORRECT_Q — ~25% recovery
    • ERROR_CORRECT_H — ~30% recovery
  • box_size — pixels per module (the small squares)
  • border — number of modules for the quiet zone around the code (minimum 4 per spec)

Data types

QR codes encode raw bytes, but scanners interpret certain prefixes as structured data:

  • URLhttps://example.com
  • Wi-FiWIFI:T:WPA;S:NetworkName;P:password;;
  • vCard — contact information in vCard format
  • Emailmailto:user@example.com
  • SMSsmsto:+1234567890:Hello
  • Plain text — any string

The library does not interpret these formats — it encodes whatever string you pass. The scanner app decides how to act on the content.

Data capacity

Maximum characters depend on version and error correction:

VersionModulesNumericAlphanumericBinary
121×21412517
1057×57652395271
2097×971,8171,101755
40177×1777,0894,2962,953

Higher error correction reduces capacity. For URLs (alphanumeric + symbols), version 5-10 covers most practical cases.

Image customization

Change colors with fill_color and back_color:

img = qr.make_image(fill_color="#2c3e50", back_color="#ecf0f1")

For advanced styling, use the StyledPilImage factory:

from qrcode.image.styledpil import StyledPilImage
from qrcode.image.styles.moduledrawers import RoundedModuleDrawer
from qrcode.image.styles.colormasks import RadialGradiantColorMask

img = qr.make_image(
    image_factory=StyledPilImage,
    module_drawer=RoundedModuleDrawer(),
    color_mask=RadialGradiantColorMask(
        center_color=(0, 0, 128),
        edge_color=(0, 128, 128)
    )
)

Module drawer options include SquareModuleDrawer (default), RoundedModuleDrawer, GappedSquareModuleDrawer, CircleModuleDrawer, and VerticalBarsDrawer.

Embedding logos

Place a logo in the center by compositing with Pillow:

from PIL import Image

qr_img = qr.make_image(fill_color="black", back_color="white").convert("RGB")
logo = Image.open("logo.png")
logo = logo.resize((60, 60))

pos = ((qr_img.size[0] - logo.size[0]) // 2,
       (qr_img.size[1] - logo.size[1]) // 2)
qr_img.paste(logo, pos)
qr_img.save("branded_qr.png")

Use ERROR_CORRECT_H when embedding logos — the 30% error recovery compensates for the obscured center modules.

SVG output

For vector output (sharp at any scale), use the SVG factory:

import qrcode
import qrcode.image.svg

qr = qrcode.QRCode(image_factory=qrcode.image.svg.SvgPathImage)
qr.add_data("https://example.com")
qr.make(fit=True)
img = qr.make_image()
img.save("output.svg")

SVG variants: SvgImage (one rect per module), SvgPathImage (single path element, smaller file), SvgFragmentImage (no XML header).

The one thing to remember: The qrcode library maps your data through version selection, error correction encoding, and module rendering to produce a scannable image — version and error correction are the two knobs that balance capacity against resilience.

pythonqrcodegenerationbarcode

See Also

  • Python Arcade Library Think of a magical art table that draws your game characters, listens when you press buttons, and cleans up the mess — that's Python Arcade.
  • Python Audio Fingerprinting Ever wonder how Shazam identifies a song from just a few seconds of noisy audio? Audio fingerprinting is the magic behind it, and Python can do it too.
  • Python Barcode Generation Picture the stripy labels on grocery items to understand how Python can create those machine-readable barcodes from numbers.
  • Python Cellular Automata Imagine a checkerboard where each square follows simple rules to turn on or off — and suddenly complex patterns emerge like magic.
  • Python Godot Gdscript Bridge Imagine speaking English to a friend who speaks French, with a translator in the middle — that's how Python talks to the Godot game engine.