11 KiB
11 KiB
Barcodes Reference
Comprehensive guide to creating barcodes and QR codes in ReportLab.
Available Barcode Types
ReportLab supports a wide range of 1D and 2D barcode formats.
1D Barcodes (Linear)
- Code128 - Compact, encodes full ASCII
- Code39 (Standard39) - Alphanumeric, widely supported
- Code93 (Standard93) - Compressed Code39
- EAN-13 - European Article Number (retail)
- EAN-8 - Short form of EAN
- EAN-5 - 5-digit add-on (pricing)
- UPC-A - Universal Product Code (North America)
- ISBN - International Standard Book Number
- Code11 - Telecommunications
- Codabar - Blood banks, FedEx, libraries
- I2of5 (Interleaved 2 of 5) - Warehouse/distribution
- MSI - Inventory control
- POSTNET - US Postal Service
- USPS_4State - US Postal Service
- FIM (A, B, C, D) - Facing Identification Mark (mail sorting)
2D Barcodes
- QR - QR Code (widely used for URLs, contact info)
- ECC200DataMatrix - Data Matrix format
Using Barcodes with Canvas
Code128 (Recommended for General Use)
Code128 is versatile and compact - encodes full ASCII character set with mandatory checksum.
from reportlab.pdfgen import canvas
from reportlab.graphics.barcode import code128
from reportlab.lib.units import inch
c = canvas.Canvas("barcode.pdf")
# Create barcode
barcode = code128.Code128("HELLO123")
# Draw on canvas
barcode.drawOn(c, 1*inch, 5*inch)
c.save()
Code128 Options
barcode = code128.Code128(
value="ABC123", # Required: data to encode
barWidth=0.01*inch, # Width of narrowest bar
barHeight=0.5*inch, # Height of bars
quiet=1, # Add quiet zones (margins)
lquiet=None, # Left quiet zone width
rquiet=None, # Right quiet zone width
stop=1, # Show stop symbol
)
# Draw with specific size
barcode.drawOn(canvas, x, y)
# Get dimensions
width = barcode.width
height = barcode.height
Code39 (Standard39)
Supports: 0-9, A-Z (uppercase), space, and special chars (-.$/+%*).
from reportlab.graphics.barcode import code39
barcode = code39.Standard39(
value="HELLO",
barWidth=0.01*inch,
barHeight=0.5*inch,
quiet=1,
checksum=0, # 0 or 1
)
barcode.drawOn(canvas, x, y)
Extended Code39
Encodes full ASCII (pairs of Code39 characters).
from reportlab.graphics.barcode import code39
barcode = code39.Extended39(
value="Hello World!", # Can include lowercase and symbols
barWidth=0.01*inch,
barHeight=0.5*inch,
)
barcode.drawOn(canvas, x, y)
Code93
from reportlab.graphics.barcode import code93
# Standard93 - uppercase, digits, some symbols
barcode = code93.Standard93(
value="HELLO93",
barWidth=0.01*inch,
barHeight=0.5*inch,
)
# Extended93 - full ASCII
barcode = code93.Extended93(
value="Hello 93!",
barWidth=0.01*inch,
barHeight=0.5*inch,
)
barcode.drawOn(canvas, x, y)
EAN-13 (European Article Number)
13-digit barcode for retail products.
from reportlab.graphics.barcode import eanbc
# Must be exactly 12 digits (13th is calculated checksum)
barcode = eanbc.Ean13BarcodeWidget(
value="123456789012"
)
# Draw
from reportlab.graphics import renderPDF
from reportlab.graphics.shapes import Drawing
d = Drawing()
d.add(barcode)
renderPDF.draw(d, canvas, x, y)
EAN-8
Short form, 8 digits.
from reportlab.graphics.barcode import eanbc
# Must be exactly 7 digits (8th is calculated)
barcode = eanbc.Ean8BarcodeWidget(
value="1234567"
)
UPC-A
12-digit barcode used in North America.
from reportlab.graphics.barcode import usps
# 11 digits (12th is checksum)
barcode = usps.UPCA(
value="01234567890"
)
barcode.drawOn(canvas, x, y)
ISBN (Books)
from reportlab.graphics.barcode.widgets import ISBNBarcodeWidget
# 10 or 13 digit ISBN
barcode = ISBNBarcodeWidget(
value="978-0-123456-78-9"
)
# With pricing (EAN-5 add-on)
barcode = ISBNBarcodeWidget(
value="978-0-123456-78-9",
price=True,
)
QR Codes
Most versatile 2D barcode - can encode URLs, text, contact info, etc.
from reportlab.graphics.barcode.qr import QrCodeWidget
from reportlab.graphics.shapes import Drawing
from reportlab.graphics import renderPDF
# Create QR code
qr = QrCodeWidget("https://example.com")
# Size in pixels (QR codes are square)
qr.barWidth = 100 # Width in points
qr.barHeight = 100 # Height in points
# Error correction level
# L = 7% recovery, M = 15%, Q = 25%, H = 30%
qr.qrVersion = 1 # Auto-size (1-40, or None for auto)
qr.errorLevel = 'M' # L, M, Q, H
# Draw
d = Drawing()
d.add(qr)
renderPDF.draw(d, canvas, x, y)
QR Code - More Options
# URL QR Code
qr = QrCodeWidget("https://example.com")
# Contact information (vCard)
vcard_data = """BEGIN:VCARD
VERSION:3.0
FN:John Doe
TEL:+1-555-1234
EMAIL:john@example.com
END:VCARD"""
qr = QrCodeWidget(vcard_data)
# WiFi credentials
wifi_data = "WIFI:T:WPA;S:NetworkName;P:Password;;"
qr = QrCodeWidget(wifi_data)
# Plain text
qr = QrCodeWidget("Any text here")
Data Matrix (ECC200)
Compact 2D barcode for small items.
from reportlab.graphics.barcode.datamatrix import DataMatrixWidget
barcode = DataMatrixWidget(
value="DATA123"
)
d = Drawing()
d.add(barcode)
renderPDF.draw(d, canvas, x, y)
Postal Barcodes
from reportlab.graphics.barcode import usps
# POSTNET (older format)
barcode = usps.POSTNET(
value="55555-1234", # ZIP or ZIP+4
)
# USPS 4-State (newer)
barcode = usps.USPS_4State(
value="12345678901234567890", # 20-digit routing code
routing="12345678901"
)
barcode.drawOn(canvas, x, y)
FIM (Facing Identification Mark)
Used for mail sorting.
from reportlab.graphics.barcode import usps
# FIM-A, FIM-B, FIM-C, or FIM-D
barcode = usps.FIM(
value="A" # A, B, C, or D
)
barcode.drawOn(canvas, x, y)
Using Barcodes with Platypus
For flowing documents, wrap barcodes in Flowables.
Simple Approach - Drawing Flowable
from reportlab.graphics.shapes import Drawing
from reportlab.graphics.barcode.qr import QrCodeWidget
from reportlab.lib.units import inch
# Create drawing
d = Drawing(2*inch, 2*inch)
# Create barcode
qr = QrCodeWidget("https://example.com")
qr.barWidth = 2*inch
qr.barHeight = 2*inch
qr.x = 0
qr.y = 0
d.add(qr)
# Add to story
story.append(d)
Custom Flowable Wrapper
from reportlab.platypus import Flowable
from reportlab.graphics.barcode import code128
from reportlab.lib.units import inch
class BarcodeFlowable(Flowable):
def __init__(self, code, barcode_type='code128', width=2*inch, height=0.5*inch):
Flowable.__init__(self)
self.code = code
self.barcode_type = barcode_type
self.width_val = width
self.height_val = height
# Create barcode
if barcode_type == 'code128':
self.barcode = code128.Code128(code, barWidth=width/100, barHeight=height)
# Add other types as needed
def draw(self):
self.barcode.drawOn(self.canv, 0, 0)
def wrap(self, availWidth, availHeight):
return (self.barcode.width, self.barcode.height)
# Use in story
story.append(BarcodeFlowable("PRODUCT123"))
Complete Examples
Product Label with Barcode
from reportlab.pdfgen import canvas
from reportlab.graphics.barcode import code128
from reportlab.lib.pagesizes import letter
from reportlab.lib.units import inch
def create_product_label(filename, product_code, product_name):
c = canvas.Canvas(filename, pagesize=(4*inch, 2*inch))
# Product name
c.setFont("Helvetica-Bold", 14)
c.drawCentredString(2*inch, 1.5*inch, product_name)
# Barcode
barcode = code128.Code128(product_code)
barcode_width = barcode.width
barcode_height = barcode.height
# Center barcode
x = (4*inch - barcode_width) / 2
y = 0.5*inch
barcode.drawOn(c, x, y)
# Code text
c.setFont("Courier", 10)
c.drawCentredString(2*inch, 0.3*inch, product_code)
c.save()
create_product_label("label.pdf", "ABC123456789", "Premium Widget")
QR Code Contact Card
from reportlab.pdfgen import canvas
from reportlab.graphics.barcode.qr import QrCodeWidget
from reportlab.graphics.shapes import Drawing
from reportlab.graphics import renderPDF
from reportlab.lib.units import inch
def create_contact_card(filename, name, phone, email):
c = canvas.Canvas(filename, pagesize=(3.5*inch, 2*inch))
# Contact info
c.setFont("Helvetica-Bold", 12)
c.drawString(0.5*inch, 1.5*inch, name)
c.setFont("Helvetica", 10)
c.drawString(0.5*inch, 1.3*inch, phone)
c.drawString(0.5*inch, 1.1*inch, email)
# Create vCard data
vcard = f"""BEGIN:VCARD
VERSION:3.0
FN:{name}
TEL:{phone}
EMAIL:{email}
END:VCARD"""
# QR code
qr = QrCodeWidget(vcard)
qr.barWidth = 1.5*inch
qr.barHeight = 1.5*inch
d = Drawing()
d.add(qr)
renderPDF.draw(d, c, 1.8*inch, 0.2*inch)
c.save()
create_contact_card("contact.pdf", "John Doe", "+1-555-1234", "john@example.com")
Shipping Label with Multiple Barcodes
from reportlab.pdfgen import canvas
from reportlab.graphics.barcode import code128
from reportlab.lib.units import inch
def create_shipping_label(filename, tracking_code, zip_code):
c = canvas.Canvas(filename, pagesize=(6*inch, 4*inch))
# Title
c.setFont("Helvetica-Bold", 16)
c.drawString(0.5*inch, 3.5*inch, "SHIPPING LABEL")
# Tracking barcode
c.setFont("Helvetica", 10)
c.drawString(0.5*inch, 2.8*inch, "Tracking Number:")
tracking_barcode = code128.Code128(tracking_code, barHeight=0.5*inch)
tracking_barcode.drawOn(c, 0.5*inch, 2*inch)
c.setFont("Courier", 9)
c.drawString(0.5*inch, 1.8*inch, tracking_code)
# Additional info can be added
c.save()
create_shipping_label("shipping.pdf", "1Z999AA10123456784", "12345")
Barcode Selection Guide
Choose Code128 when:
- General purpose encoding
- Need to encode numbers and letters
- Want compact size
- Widely supported
Choose Code39 when:
- Older systems require it
- Don't need lowercase letters
- Want maximum compatibility
Choose QR Code when:
- Need to encode URLs
- Want mobile device scanning
- Need high data capacity
- Want error correction
Choose EAN/UPC when:
- Retail product identification
- Need industry-standard format
- Global distribution
Choose Data Matrix when:
- Very limited space
- Small items (PCB, electronics)
- Need 2D compact format
Best Practices
- Test scanning early with actual barcode scanners/readers
- Add quiet zones (white space) around barcodes - set
quiet=1 - Choose appropriate height - taller barcodes are easier to scan
- Include human-readable text below barcode for manual entry
- Use Code128 as default for general purpose - it's compact and versatile
- For URLs, use QR codes - much easier for mobile users
- Check barcode standards for your industry (retail uses EAN/UPC)
- Test print quality - low DPI can make barcodes unscannable
- Validate data before encoding - wrong check digits cause issues
- Consider error correction for QR codes - use 'M' or 'H' for important data