qrcode generates QR codes as PNG, SVG, or console art. pip install qrcode[pil]. Quick: import qrcode; img = qrcode.make("https://example.com"); img.save("qr.png"). Full control: qr = qrcode.QRCode(version=1, error_correction=qrcode.constants.ERROR_CORRECT_H, 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("qr.png"). Error correction: ERROR_CORRECT_L (7%), ERROR_CORRECT_M (15%), ERROR_CORRECT_Q (25%), ERROR_CORRECT_H (30%) — higher = more redundancy, allows partial damage. version: 1–40, controls size. fit=True — auto pick smallest version. Colors: make_image(fill_color="darkblue", back_color="#FAFAFA"). fill_color=(0,0,128) — RGB tuple. SVG: import qrcode.image.svg; qr.make_image(image_factory=qrcode.image.svg.SvgImage). SvgFillImage for path-only SVG. SvgPathImage for clean SVG path. Bytes: io_buf = io.BytesIO(); img.save(io_buf); io_buf.seek(0); data = io_buf.getvalue(). Terminal: qr.print_ascii(). qr.print_tty() — black/white blocks. Styled: from qrcode.image.styledpil import StyledPilImage; from qrcode.image.styles.moduledrawers.pil import RoundedModuleDrawer. qr.make_image(image_factory=StyledPilImage, module_drawer=RoundedModuleDrawer()). Batch: generate QR codes for a list of URLs. Claude Code generates qrcode pipelines, batch generators, and Flask QR endpoints.
CLAUDE.md for qrcode
## qrcode Stack
- Version: qrcode >= 7.4 | pip install "qrcode[pil]"
- Quick: qrcode.make(data).save("qr.png") — one line for PNG output
- Full: QRCode(error_correction=ERROR_CORRECT_H, box_size=10, border=4)
- Add: qr.add_data(data); qr.make(fit=True) — fit picks smallest version
- Image: img = qr.make_image(fill_color="black", back_color="white")
- SVG: image_factory=qrcode.image.svg.SvgImage for vector output
- Bytes: save to io.BytesIO for HTTP response without temp file
qrcode QR Code Generation Pipeline
# app/qr_gen.py — qrcode PNG, SVG, and styled QR code generation
from __future__ import annotations
import base64
import io
from enum import Enum
from pathlib import Path
from typing import Any
import qrcode
import qrcode.image.svg
from qrcode.constants import (
ERROR_CORRECT_H,
ERROR_CORRECT_L,
ERROR_CORRECT_M,
ERROR_CORRECT_Q,
)
# ─────────────────────────────────────────────────────────────────────────────
# 1. Quick generation helpers
# ─────────────────────────────────────────────────────────────────────────────
def make_qr_png(
data: str,
box_size: int = 10,
border: int = 4,
fill_color: str | tuple = "black",
back_color: str | tuple = "white",
error_correction=ERROR_CORRECT_M,
) -> bytes:
"""
Generate a QR code and return as PNG bytes.
error_correction=ERROR_CORRECT_H allows up to 30% of the code to be damaged.
box_size=10 means each "pixel" of the QR is 10×10 display pixels.
border=4 is the minimum quiet zone required by the QR spec.
"""
qr = qrcode.QRCode(
error_correction=error_correction,
box_size=box_size,
border=border,
)
qr.add_data(data)
qr.make(fit=True)
img = qr.make_image(fill_color=fill_color, back_color=back_color)
buf = io.BytesIO()
img.save(buf, format="PNG")
return buf.getvalue()
def make_qr_svg(data: str, border: int = 4) -> str:
"""
Generate a QR code as an SVG string.
SvgImage produces an SVG with individual rects per module.
SvgPathImage produces a single <path> element — smaller file.
"""
qr = qrcode.QRCode(
error_correction=ERROR_CORRECT_M,
border=border,
)
qr.add_data(data)
qr.make(fit=True)
factory = qrcode.image.svg.SvgPathImage
img = qr.make_image(image_factory=factory)
buf = io.BytesIO()
img.save(buf)
return buf.getvalue().decode("utf-8")
def make_qr_base64(data: str, **kwargs) -> str:
"""
Generate a QR code PNG and return as base64-encoded string.
Ready for embedding in HTML: <img src="data:image/png;base64,{result}">
"""
png_bytes = make_qr_png(data, **kwargs)
return base64.b64encode(png_bytes).decode("ascii")
def save_qr(data: str, path: str | Path, **kwargs) -> Path:
"""Generate a QR code PNG and save to disk."""
png = make_qr_png(data, **kwargs)
p = Path(path)
p.write_bytes(png)
return p
# ─────────────────────────────────────────────────────────────────────────────
# 2. Styled QR codes (rounded, colored modules)
# ─────────────────────────────────────────────────────────────────────────────
def make_styled_qr(
data: str,
fill_color: tuple[int, int, int] = (0, 0, 0),
back_color: tuple[int, int, int] = (255, 255, 255),
box_size: int = 12,
border: int = 4,
style: str = "rounded",
) -> bytes:
"""
Generate a styled QR code using StyledPilImage.
style="rounded" uses RoundedModuleDrawer for soft corners.
style="circle" uses CircleModuleDrawer.
style="square" uses the default square modules.
Requires: pip install "qrcode[pil]"
"""
try:
from qrcode.image.styledpil import StyledPilImage
from qrcode.image.styles.moduledrawers.pil import (
CircleModuleDrawer,
GappedSquareModuleDrawer,
RoundedModuleDrawer,
SquareModuleDrawer,
VerticalBarsDrawer,
)
drawers = {
"rounded": RoundedModuleDrawer(),
"circle": CircleModuleDrawer(),
"square": SquareModuleDrawer(),
"gapped": GappedSquareModuleDrawer(),
"vertical": VerticalBarsDrawer(),
}
drawer = drawers.get(style, RoundedModuleDrawer())
except ImportError:
# Fall back to standard image if styledpil not available
return make_qr_png(data, box_size=box_size, border=border,
fill_color=fill_color, back_color=back_color)
qr = qrcode.QRCode(
error_correction=ERROR_CORRECT_H, # H for logo embedding (30% redundancy)
box_size=box_size,
border=border,
)
qr.add_data(data)
qr.make(fit=True)
img = qr.make_image(
image_factory=StyledPilImage,
module_drawer=drawer,
color_mask=None,
)
# Recolor using PIL
img_pil = img.convert("RGBA")
# Simple color replacement: black → fill_color
data_pixels = img_pil.load()
for y in range(img_pil.height):
for x in range(img_pil.width):
r, g, b, a = data_pixels[x, y]
if r < 128:
data_pixels[x, y] = (*fill_color, 255)
else:
data_pixels[x, y] = (*back_color, 255)
buf = io.BytesIO()
img_pil.save(buf, format="PNG")
return buf.getvalue()
# ─────────────────────────────────────────────────────────────────────────────
# 3. QR with embedded logo
# ─────────────────────────────────────────────────────────────────────────────
def make_qr_with_logo(
data: str,
logo_path: str | Path | None = None,
logo_size_ratio: float = 0.25,
box_size: int = 12,
) -> bytes:
"""
Embed a logo in the center of a QR code.
Uses ERROR_CORRECT_H so the QR still scans with the logo covering ~25%.
Requires Pillow: pip install "qrcode[pil]"
"""
from PIL import Image
png_bytes = make_qr_png(
data,
box_size=box_size,
border=4,
error_correction=ERROR_CORRECT_H,
)
qr_img = Image.open(io.BytesIO(png_bytes)).convert("RGBA")
if logo_path:
logo = Image.open(str(logo_path)).convert("RGBA")
else:
# Create a placeholder colored square as the "logo"
logo_size = int(qr_img.width * logo_size_ratio)
logo = Image.new("RGBA", (logo_size, logo_size), (70, 130, 180, 255))
# Resize logo to fit ratio
max_logo = int(qr_img.width * logo_size_ratio)
logo.thumbnail((max_logo, max_logo), Image.LANCZOS)
# Center the logo
pos = (
(qr_img.width - logo.width) // 2,
(qr_img.height - logo.height) // 2,
)
qr_img.paste(logo, pos, mask=logo)
buf = io.BytesIO()
qr_img.save(buf, format="PNG")
return buf.getvalue()
# ─────────────────────────────────────────────────────────────────────────────
# 4. Batch generation
# ─────────────────────────────────────────────────────────────────────────────
def batch_generate(
items: list[dict[str, str]],
output_dir: str | Path,
key_field: str = "url",
name_field: str = "name",
) -> list[Path]:
"""
Generate QR codes for a list of items.
Each item must have a key_field (data to encode) and name_field (filename).
Returns list of generated file paths.
"""
output_dir = Path(output_dir)
output_dir.mkdir(parents=True, exist_ok=True)
paths = []
for item in items:
data = item.get(key_field, "")
name = item.get(name_field, data[:20].replace("/", "_"))
if not data:
continue
path = output_dir / f"{name}.png"
save_qr(data, path)
paths.append(path)
return paths
# ─────────────────────────────────────────────────────────────────────────────
# 5. Flask response helper
# ─────────────────────────────────────────────────────────────────────────────
FLASK_EXAMPLE = '''
from flask import Flask, Response, request
from app.qr_gen import make_qr_png, make_qr_svg
app = Flask(__name__)
@app.get("/qr.png")
def qr_png():
data = request.args.get("data", "https://example.com")
png = make_qr_png(data)
return Response(png, mimetype="image/png",
headers={"Cache-Control": "public, max-age=86400"})
@app.get("/qr.svg")
def qr_svg():
data = request.args.get("data", "https://example.com")
svg = make_qr_svg(data)
return Response(svg, mimetype="image/svg+xml")
'''
# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
print("=== PNG QR code ===")
png = make_qr_png("https://claudeskills360.com", box_size=10, border=4)
Path("/tmp/qr_basic.png").write_bytes(png)
print(f" Written {len(png):,} bytes to /tmp/qr_basic.png")
print("\n=== SVG QR code ===")
svg = make_qr_svg("https://claudeskills360.com")
Path("/tmp/qr.svg").write_text(svg)
print(f" Written {len(svg):,} chars to /tmp/qr.svg")
print("\n=== Base64 (for HTML embedding) ===")
b64 = make_qr_base64("https://claudeskills360.com")
print(f" base64 length: {len(b64)} chars")
print(f" HTML: <img src=\"data:image/png;base64,{b64[:40]}...\">")
print("\n=== Batch generation ===")
import tempfile
with tempfile.TemporaryDirectory() as tmp:
items = [
{"url": "https://claudeskills360.com", "name": "home"},
{"url": "https://claudeskills360.com/free/","name": "free"},
{"url": "https://claudeskills360.com/blog/","name": "blog"},
]
paths = batch_generate(items, tmp, key_field="url", name_field="name")
print(f" Generated {len(paths)} QR codes")
for p in paths:
print(f" {p.name}: {p.stat().st_size:,} bytes")
print("\n=== Error correction levels ===")
levels = [
(ERROR_CORRECT_L, "L (7%)"),
(ERROR_CORRECT_M, "M (15%)"),
(ERROR_CORRECT_Q, "Q (25%)"),
(ERROR_CORRECT_H, "H (30%)"),
]
for ec, label in levels:
png = make_qr_png("https://example.com", error_correction=ec)
print(f" {label}: {len(png):,} bytes")
For the pyqrcode alternative — pyqrcode uses a different API (pyqrcode.create(data).png("file.png", scale=6)) and hasn’t been updated recently; qrcode is more actively maintained, supports custom colors, all four error correction levels, PNG/SVG output, and StyledPilImage for rounded or circled module shapes with a single pip install "qrcode[pil]". For the segno alternative — segno is a newer, more feature-complete QR/Micro-QR library with cleaner SVG output and better JPEG/EPS support, but qrcode is the most widely deployed Python QR library, has the largest number of examples and StackOverflow answers, and its QRCode class API is straightforward enough for the most common use cases — generating a PNG, setting error correction, and embedding in a Flask response. The Claude Skills 360 bundle includes qrcode skill sets covering qrcode.make() one-liner, QRCode class with error_correction/box_size/border, add_data() + make(fit=True), make_image() with fill_color/back_color, ERROR_CORRECT_L/M/Q/H constants, io.BytesIO for in-memory PNG, SvgPathImage for vector output, make_qr_base64() for HTML img tag embedding, StyledPilImage with RoundedModuleDrawer, make_qr_with_logo() logo embedding, batch_generate() for bulk generation, and Flask QR endpoint patterns. Start with the free tier to try QR code generation code generation.