Source code for pyphyschemtools.misc

import os
from PIL import Image
from qrcode import QRCode
from IPython.display import display, Image as IPImage

[docs] class QRCodeGenerator: """ A utility class to generate QR codes with embedded logos for pyphyschemtools. Initialize the generator with specific QR parameters. Args: box_size (int): The size of each box in the QR code grid. border (int): The thickness of the white border. version (int): The complexity of the QR code (1 to 40). """ def __init__(self, box_size=40, border=1, version=4): self.box_size = box_size self.border = border self.version = version
[docs] def generate(self, url, logo_path, fill_color="#1a525f", back_color="white", save_path=None, logo_ratio=4, width=250, flatten=False): """ Creates a QR code with a centered logo, saves it to disk, and displays it. If save_path is not provided, the image is saved in the logo's directory with a ``qrcode_`` prefix. Args: url (str): The target URL for the QR code. logo_path (str): Path to the logo image file. fill_color (str): Hex code or name for the QR code color. back_color (str): Background color. save_path (str, optional): Custom path to save the PNG. Defaults to None. logo_ratio (float): Ratio of logo size relative to QR code size (default 1/4). width (int): Display width for Jupyter Notebook rendering. flatten (bool): If True, removes transparency by placing the logo on a solid white background. Defaults to False. Returns: PIL.Image: The generated QR code image object. """ # 1. Initialize and build the QR Code qr = QRCode(version=self.version, box_size=self.box_size, border=self.border) qr.add_data(url) qr.make(fit=True) # 2. Create base image img = qr.make_image(fill_color=fill_color, back_color=back_color).convert("RGBA") # 3. Handle Logo embedding and Path generation if os.path.exists(logo_path): logo = Image.open(logo_path).convert("RGBA") # --- Optional: Remove Alpha Channel (Flattening) --- if flatten: # Create a solid white background matching the logo's current size background = Image.new("RGBA", logo.size, (255, 255, 255, 255)) # Composite the logo over the white background logo = Image.alpha_composite(background, logo).convert("RGB") # Calculate aspect ratio original_width, original_height = logo.size aspect_ratio = original_width / original_height # Target size for the larger dimension target_max_dim = int(img.size[0] / logo_ratio) if original_width > original_height: # Landscape or wide logo new_width = target_max_dim new_height = int(target_max_dim / aspect_ratio) else: # Portrait or tall logo new_height = target_max_dim new_width = int(target_max_dim * aspect_ratio) # Resize while maintaining aspect ratio logo = logo.resize((new_width, new_height), Image.Resampling.LANCZOS) # Center position img_w, img_h = img.size logo_w, logo_h = logo.size pos = ((img_w - logo_w) // 2, (img_h - logo_h) // 2) # Paste logo using alpha channel as mask if logo.mode == 'RGBA': img.paste(logo, pos, mask=logo.split()[3]) else: img.paste(logo, pos) # Define automatic save path if none provided if save_path is None: directory = os.path.dirname(logo_path) filename = os.path.basename(logo_path) save_path = os.path.join(directory, f"qrcode_{filename}") else: if save_path is None: save_path = "qrcode_no_logo.png" print(f"Warning: Logo path '{logo_path}' not found. Generating QR without logo.") # 4. Save to disk and display in Jupyter img.save(save_path) display(IPImage(filename=save_path, width=width)) return img