Skip to content

Latest commit

Β 

History

127 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

pyrxing

pyrxing is a fast, dependency-free Python barcode/QR code reader built using zxing-cpp Rust bindings via PyO3.

This library offers efficient barcode scanning in pure Python environments, with pre-built native wheels β€” including full support for Alpine Linux and musl-based systems where the official zxing-cpp Python package requires additional build steps.


πŸš€ Features

  • ⚑ High performance: Powered by zxing-cpp 0.5.2 C++ library through optimized Rust bindings with excellent barcode detection performance
  • 🐍 Python-native API: Simple interface with just two functions: read_barcode and read_barcodes
  • πŸ“¦ No system dependencies: No need for zbar, JRE, or any external libraries
  • πŸ— Alpine Linux compatible: Pre-built musllinux wheels available (no build required)
  • 🧠 Type hinting & autocompletion: Includes .pyi stub files with 32 barcode format variants
  • πŸ”’ Safe and minimal: No unnecessary features β€” just barcode reading
  • ⚑ Competitive performance: Matches or exceeds official zxing-cpp Python bindings across all formats

βœ… Supported Environments

Platforms

  • Linux (manylinux & musllinux wheels)
    • Architectures: x86_64, aarch64
  • macOS
    • Universal binaries for both Intel and Apple Silicon (arm64)
  • Windows
    • Architectures: x64

Python Versions

Python 3.11 - 3.14


πŸ“¦ Installation

Install with pip:

pip install pyrxing

Recommended for Alpine Linux/musl environments: While the official zxing-cpp Python package requires building from source on musl-based systems, pyrxing provides pre-built wheels for immediate installation.


πŸ“Š Performance

pyrxing delivers competitive performance across a comprehensive range of barcode formats, matching or exceeding the official zxing-cpp Python bindings:

Performance Summary:

  • Single detection: Comparable performance with zxing-cpp (within Β±26% across all formats)
  • Multiple detection: Comparable performance with zxing-cpp (within Β±18% across all formats)
  • Overall: Nearly identical median performance, with pyrxing being faster on most formats

Benchmark Results (ΞΌs per decode)

read_barcode() - Single Barcode Detection

Format pyrxing zxing-cpp Difference
Micro QR 65.2 68.4 5% faster
rMQR 73.9 74.7 1% faster
Aztec 84.0 85.7 2% faster
DataBar 192.4 193.6 1% faster
DataBar Ltd. 190.1 192.6 1% faster
Data Matrix 246.4 334.2 26% faster
Code 93 272.6 274.8 1% faster
DX Film Edge 293.3 336.3 13% faster
QR Code 299.6 304.5 2% faster
ITF 340.1 412.2 17% faster
DataBar Exp. 360.3 357.6 1% slower
PDF417 368.1 406.7 9% faster
Codabar 412.6 473.7 13% faster
UPC-E 548.9 687.9 20% faster
EAN-8 863.0 1084.3 20% faster
MaxiCode 923.8 1052.4 12% faster
Code 39 1042.9 1249.8 17% faster
EAN-13 1111.1 1403.8 21% faster
UPC-A 1123.4 1412.0 20% faster
Code 128 2171.9 2638.8 18% faster

read_barcodes() - Multiple Barcode Detection

Format pyrxing zxing-cpp Difference
Micro QR 470.8 471.9 0% faster
rMQR 539.0 542.1 1% faster
Aztec 649.1 652.6 1% faster
DataBar Ltd. 741.3 741.8 0% faster
DataBar 781.7 782.1 0% faster
PDF417 990.1 1024.5 3% faster
Code 93 1091.8 1095.1 0% faster
Data Matrix 1142.0 1223.8 7% faster
ITF 1208.8 1277.6 5% faster
Codabar 1437.5 1490.8 4% faster
DataBar Exp. 1508.9 1508.9 0% faster
DX Film Edge 1509.2 1835.6 18% faster
UPC-E 2159.3 2405.4 10% faster
QR Code 2477.5 2484.5 0% faster
MaxiCode 2821.3 2910.4 3% faster
EAN-8 2964.1 3211.3 8% faster
Code 39 3423.3 3621.0 5% faster
UPC-A 4796.1 5359.9 11% faster
EAN-13 4888.4 5377.9 9% faster
Code 128 8671.9 9107.1 5% faster

Benchmark Environment

  • OS: macOS Sequoia 15.2 (Apple Silicon)
  • CPU: Apple M1 Max
  • Python: 3.13.10
  • Libraries: pyrxing 0.4.4 (zxing-cpp 0.5.0), zxing-cpp 3.0.0, Pillow 12.1.1
  • Method: Median of 100 runs with 20-run warm-up

Test Images: Located in assets/ directory:

  • 1D Barcodes: test_codabar.png, test_code39.png, test_code93.png, test_code128.png, test_ean8.png, test_ean13.png, test_itf.png, test_upc_a.png, test_upc_e.png, test_data_bar.png, test_data_bar_expanded.png, test_data_bar_limited.png
  • 2D Barcodes: test_qr_code.png, test_micro_qr.png, test_rmqr.png, test_aztec.png, test_data_matrix.png, test_pdf417.png, test_maxi_code.png
  • Specialty: test_dx_film_edge.png

Reproduce benchmarks: See benchmark.py for the complete benchmark script.


πŸ§ͺ Usage

from pyrxing import read_barcode, read_barcodes

# Read a single barcode from an image path
barcode = read_barcode("example.png")

# Read multiple barcodes from an image
barcodes = read_barcodes("example.png")

# Optionally filter by barcode format
barcodes = read_barcodes("example.png", formats=['QRCode'])

You can also pass an object that conforms to the ImageProtocol instead of a path.

from pyrxing import read_barcode
from PIL import Image
# Read a single barcode from PIL.Image.Image object
barcode = read_barcode(Image.open("example.png"))

🚫 Not Planned

  • ❌ Barcode generation

πŸ“š API Reference

For full API and type hints, see pyrxing.pyi or use your IDE's autocomplete.

import os
from typing import Any, Literal, Protocol

BarcodeFormat = Literal[
    "Aztec",
    "AztecCode",
    "AztecRune",
    "Codabar",
    "Code39",
    "Code93",
    "Code128",
    "CompactPDF417",
    "DataBar",
    "DataBarExpanded",
    "DataBarExpandedStacked",
    "DataBarLimited",
    "DataBarOmni",
    "DataBarStacked",
    "DataBarStackedOmni",
    "DataMatrix",
    "DXFilmEdge",
    "EAN2",
    "EAN5",
    "EAN8",
    "EAN13",
    "EANUPC",
    "ISBN",
    "ITF",
    "MaxiCode",
    "MicroPDF417",
    "MicroQRCode",
    "PDF417",
    "PZN",
    "QRCode",
    "QRCodeModel1",
    "QRCodeModel2",
    "RMQRCode",
    "UPCA",
    "UPCE",
]


class ImageProtocol(Protocol):
    @property
    def mode(self) -> str: ...

    @property
    def width(self) -> int: ...

    @property
    def height(self) -> int: ...

    def tobytes(self) -> bytes:
        """return pixel data as byte array"""

    def convert(self, mode: str) -> Any: ...

    def load(self): ...


class Error(Exception):
    """Base class of every exception the module raises."""


class BarcodeDecodeError(Error):
    """The reader backend failed to decode the image."""


class ImageError(Error):
    """The image cannot be used: unreadable, of an unsupported mode, or malformed."""


class UnsupportedFormatError(Error):
    """A requested barcode format name is not supported."""

    @property
    def format(self) -> str:
        """The rejected barcode format name."""


class Point:
    @property
    def x(self) -> int: ...

    @property
    def y(self) -> int: ...

class DecodeResult:
    @property
    def text(self) -> str: ...

    @property
    def points(self) -> list[Point]: ...

    @property
    def format(self) -> str: ...


def read_barcode(image: str | os.PathLike[str] | ImageProtocol, *, formats: list[BarcodeFormat] | None = None) -> DecodeResult | None: ...
def read_barcodes(image: str | os.PathLike[str] | ImageProtocol, *, formats: list[BarcodeFormat] | None = None) -> list[DecodeResult]: ...

License

Apache License 2.0

Releases

Packages

Used by

Contributors

Languages