Generating, Styling, and Decoding Barcodes & 2D Codes in Python: Complete Guide
Generating and decoding barcodes is a foundational requirement across retail, inventory logistics, digital asset tracking, and ticketing systems. In Python, creating industry-standard 1D barcodes and 2D QR codes requires only a few lines of code with specialized libraries.
This guide provides a comprehensive manual on generating vector (SVG) and raster (PNG/JPEG) barcodes with python-barcode, styling dimensions, suppressing human-readable label text, and decoding codes in images or video streams with pyzbar and OpenCV.
Core Generation Toolkit: python-barcode and Pillowโ
The python-barcode library supports all major 1D barcode symbologies, including EAN-13, Code 128, UPC-A, and ISBN-13. To output raster image formats (PNG, JPEG), install the optional pillow dependency.
Installationโ
pip install "python-barcode[images]" Pillow pyzbar opencv-python
Barcode Symbology Selection Guideโ
| Symbology | Character Set & Constraints | Primary Industry Use Case |
|---|---|---|
| Code 128 | Full ASCII 128-character set (letters, digits, symbols). | Logistics, warehouse bin tracking, shipping labels. |
| EAN-13 | Exactly 12 digits + 1 calculated checksum digit. | International retail point-of-sale products. |
| UPC-A | 12 numeric digits. | North American retail point-of-sale. |
| ISBN-13 | 13 digits starting with 978 or 979. | Book publishing and library cataloging. |
Generating Vector and Raster Barcodesโ
1. Generating Scalable SVG Barcodes (Default)โ
SVGs are vector-based and infinitely scalable, making them ideal for web rendering:
import barcode
# Select Code 128 symbology
code128_cls = barcode.get_barcode_class("code128")
my_barcode = code128_cls("LOGISTICS-ASSET-98765")
# Save as SVG file (extension added automatically)
output_path = my_barcode.save("asset_tag")
print(f"Vector barcode written to: {output_path}")
2. Generating High-Resolution PNG Images with Custom Optionsโ
For physical thermal printing, pass ImageWriter and configure module widths and quiet zones:
import barcode
from barcode.writer import ImageWriter
def generate_raster_barcode(data: str, filename: str):
code128_cls = barcode.get_barcode_class("code128")
my_barcode = code128_cls(data, writer=ImageWriter())
options = {
"module_width": 0.25, # Width of the thinnest bar (mm)
"module_height": 15.0, # Height of the bars (mm)
"font_size": 10, # Human-readable font size
"text_distance": 4.0, # Margin between bars and text label
"quiet_zone": 6.5, # White-space padding on edges
"background": "white",
"foreground": "black"
}
my_barcode.save(filename, options=options)
generate_raster_barcode("ASSET-ID-001", "asset_tag")
Removing Human-Readable Text Under Barcodesโ
By default, python-barcode renders the encoded string directly beneath the bars. When creating compact labels, embedding barcodes into UI components, or generating machine-only scans, suppress the text using 'write_text': False:
import barcode
from barcode.writer import ImageWriter
def generate_textless_barcode(data: str, output_name: str):
ean_cls = barcode.get_barcode_class("ean13")
ean = ean_cls(data, writer=ImageWriter())
options = {
"write_text": False, # Suppresses human-readable label
"module_width": 0.3,
"module_height": 18.0,
"quiet_zone": 3.0
}
ean.save(output_name, options=options)
generate_textless_barcode("5901234123457", "barcode_no_text")
Generating Retail-Compliant EAN-13 Barcodesโ
EAN-13 requires exactly 12 payload digits. The 13th modulo-10 checksum digit is calculated and appended automatically:
from barcode import EAN13
from barcode.writer import ImageWriter
def create_retail_ean13(twelve_digits: str, filename: str):
if len(twelve_digits) != 12 or not twelve_digits.isdigit():
raise ValueError("EAN-13 payload must be exactly 12 numeric digits.")
with open(f"{filename}.png", "wb") as f:
EAN13(twelve_digits, writer=ImageWriter()).write(f)
create_retail_ean13("123456789012", "retail_sku")
Decoding Barcodes and 2D Codes with pyzbar and OpenCVโ
To detect and decode barcodes programmatically from static image files or camera video streams:
import cv2
from pyzbar.pyzbar import decode
def decode_barcode_image(image_path: str):
img = cv2.imread(image_path)
if img is None:
raise FileNotFoundError(f"Cannot open image: {image_path}")
detected_codes = decode(img)
for code in detected_codes:
payload = code.data.decode("utf-8")
symbology = code.type
bounding_box = code.rect
print(f"Decoded {symbology}: '{payload}' at {bounding_box}")
return detected_codes
if __name__ == "__main__":
decode_barcode_image("asset_tag.png")
Best Practices and Verificationโ
- Respect Quiet Zones: Maintain at least 10x the module width on both sides of the barcode. Truncating quiet zones prevents hardware scanners from establishing synchronization.
- Test Physical DPI: Print barcodes at 300 DPI or higher to avoid aliasing artifacts that blur high-density symbologies (such as Code 128).
- Hardware Validation: Always verify barcodes using physical handheld scanners and smartphone cameras prior to bulk printing.
Sources & Technical Referencesโ
- [1] python-barcode Repository: WhyNotHugo / python-barcode
- [2] Pillow Imaging Documentation: Pillow Image Processing
- [3] PyZbar Documentation: NaturalHistoryMuseum / pyzbar
- [4] OpenCV Python Tutorials: OpenCV Image Processing and Transforms
- [5] GS1 Standard: EAN-13 International Article Number Specification
