Files
KCAPDemoServer/barcode_generator.py
2025-05-08 20:49:15 -04:00

186 lines
5.5 KiB
Python

import os
import io
from PIL import Image, ImageDraw, ImageFont
# Try to import barcode libraries, provide fallback if not available
try:
import qrcode
QRCODE_AVAILABLE = True
except ImportError:
QRCODE_AVAILABLE = False
try:
from barcode import EAN13, Code128
from barcode.writer import ImageWriter
BARCODE_AVAILABLE = True
except ImportError:
BARCODE_AVAILABLE = False
class BarcodeGenerator:
"""
A utility class for generating QR codes and barcodes.
"""
@staticmethod
def check_dependencies():
"""
Check if all required dependencies are installed.
Returns:
dict: Status of each dependency
"""
return {
'qrcode': QRCODE_AVAILABLE,
'barcode': BARCODE_AVAILABLE,
'pillow': True # PIL/Pillow is imported directly at the top level
}
@staticmethod
def generate_qr_code(data, size=10, border=4):
"""
Generates a QR code as a PIL Image object.
Args:
data (str): The data to encode in the QR code
size (int): The size of the QR code (1-40)
border (int): The border size of the QR code
Returns:
PIL.Image: The generated QR code image or a placeholder image if qrcode is not available
"""
if not QRCODE_AVAILABLE:
return BarcodeGenerator._generate_placeholder("QR Code Unavailable\nPlease install 'qrcode' package")
qr = qrcode.QRCode(
version=size,
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=10,
border=border,
)
qr.add_data(data)
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white")
return img
@staticmethod
def generate_ean13_barcode(data):
"""
Generates an EAN-13 barcode as a PIL Image object.
Args:
data (str): The data to encode in the barcode (must be 12 digits)
Returns:
PIL.Image: The generated barcode image or a placeholder image if barcode is not available
"""
if not BARCODE_AVAILABLE:
return BarcodeGenerator._generate_placeholder("EAN-13 Unavailable\nPlease install 'python-barcode' package")
# Pad data to 12 digits if needed
if len(data) < 12:
data = data.zfill(12)
elif len(data) > 12:
data = data[:12]
# Create a BytesIO object to temporarily store the image
buffer = io.BytesIO()
EAN13(data, writer=ImageWriter()).write(buffer)
# Create a PIL Image from the BytesIO object
buffer.seek(0)
image = Image.open(buffer)
return image
@staticmethod
def generate_code128_barcode(data):
"""
Generates a Code 128 barcode as a PIL Image object.
Args:
data (str): The data to encode in the barcode
Returns:
PIL.Image: The generated barcode image or a placeholder image if barcode is not available
"""
if not BARCODE_AVAILABLE:
return BarcodeGenerator._generate_placeholder("Code 128 Unavailable\nPlease install 'python-barcode' package")
# Create a BytesIO object to temporarily store the image
buffer = io.BytesIO()
Code128(data, writer=ImageWriter()).write(buffer)
# Create a PIL Image from the BytesIO object
buffer.seek(0)
image = Image.open(buffer)
return image
@staticmethod
def _generate_placeholder(message):
"""
Generates a placeholder image with a message.
Args:
message (str): Message to display on the placeholder
Returns:
PIL.Image: The generated placeholder image
"""
# Create a placeholder image
img = Image.new('RGB', (300, 150), color=(255, 255, 255))
d = ImageDraw.Draw(img)
# Draw a border
d.rectangle([0, 0, 299, 149], outline=(0, 0, 0), width=2)
# Add text
try:
# Try to use a default font
font = ImageFont.truetype("arial.ttf", 20)
except IOError:
# Fallback to default font
font = ImageFont.load_default()
# Center the text
lines = message.split('\n')
y_offset = 40
for line in lines:
text_width = d.textlength(line, font=font)
d.text(((300 - text_width) // 2, y_offset), line, font=font, fill=(0, 0, 0))
y_offset += 30
return img
@staticmethod
def save_image(image, path):
"""
Saves a PIL Image to the specified path.
Args:
image (PIL.Image): The image to save
path (str): The path to save the image to
Returns:
str: The path where the image was saved
"""
image.save(path)
return path
@staticmethod
def get_image_as_bytes(image, format='PNG'):
"""
Converts a PIL Image to bytes.
Args:
image (PIL.Image): The image to convert
format (str): The format to save the image as
Returns:
bytes: The image as bytes
"""
buffer = io.BytesIO()
image.save(buffer, format=format)
return buffer.getvalue()