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
Noneor usefit=Trueto auto-select. - error_correction — how much damage the code can survive:
ERROR_CORRECT_L— ~7% recoveryERROR_CORRECT_M— ~15% recovery (default)ERROR_CORRECT_Q— ~25% recoveryERROR_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:
- URL —
https://example.com - Wi-Fi —
WIFI:T:WPA;S:NetworkName;P:password;; - vCard — contact information in vCard format
- Email —
mailto:user@example.com - SMS —
smsto:+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:
| Version | Modules | Numeric | Alphanumeric | Binary |
|---|---|---|---|---|
| 1 | 21×21 | 41 | 25 | 17 |
| 10 | 57×57 | 652 | 395 | 271 |
| 20 | 97×97 | 1,817 | 1,101 | 755 |
| 40 | 177×177 | 7,089 | 4,296 | 2,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.
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.