""" QR Code generation utilities """ import os import qrcode from qrcode.image.styledpil import StyledPilImage from qrcode.image.styles.moduledrawers import RoundedModuleDrawer, CircleModuleDrawer, SquareModuleDrawer from qrcode.image.svg import SvgPathImage, SvgFragmentImage, SvgFillImage from PIL import Image import io class QRCodeGenerator: def __init__(self): self.default_settings = { 'size': 10, 'border': 4, 'error_correction': qrcode.constants.ERROR_CORRECT_M, 'foreground_color': '#000000', 'background_color': '#FFFFFF', 'style': 'square' } def generate_qr_code(self, data, settings=None, format='PNG'): """Generate QR code with custom settings in PNG or SVG format""" if settings is None: settings = self.default_settings.copy() else: merged_settings = self.default_settings.copy() merged_settings.update(settings) settings = merged_settings if format.upper() == 'SVG': return self._generate_svg_qr_code(data, settings) else: return self._generate_png_qr_code(data, settings) def _generate_png_qr_code(self, data, settings): """Generate PNG QR code (existing functionality)""" # Create QR code instance qr = qrcode.QRCode( version=1, error_correction=settings['error_correction'], box_size=settings['size'], border=settings['border'], ) qr.add_data(data) qr.make(fit=True) # For styled QR codes with custom module drawer if settings['style'] != 'square': # Choose module drawer based on style module_drawer = None if settings['style'] == 'rounded': module_drawer = RoundedModuleDrawer() elif settings['style'] == 'circle': module_drawer = CircleModuleDrawer() # Generate the styled image img = qr.make_image( image_factory=StyledPilImage, module_drawer=module_drawer, fill_color=settings['foreground_color'], back_color=settings['background_color'] ) else: # Generate standard image with custom colors img = qr.make_image( fill_color=settings['foreground_color'], back_color=settings['background_color'] ) return img def _generate_svg_qr_code(self, data, settings): """Generate SVG QR code""" # Create QR code instance qr = qrcode.QRCode( version=1, error_correction=settings['error_correction'], box_size=settings['size'], border=settings['border'], ) qr.add_data(data) qr.make(fit=True) # Choose SVG image factory based on style if settings['style'] == 'circle': # Use SvgFillImage for better circle support factory = SvgFillImage else: # Use SvgPathImage for square and rounded styles factory = SvgPathImage # Generate SVG image img = qr.make_image( image_factory=factory, fill_color=settings['foreground_color'], back_color=settings['background_color'] ) return img def generate_qr_code_svg_string(self, data, settings=None): """Generate QR code as SVG string""" svg_img = self.generate_qr_code(data, settings, format='SVG') # Convert SVG image to string svg_buffer = io.BytesIO() svg_img.save(svg_buffer) svg_buffer.seek(0) return svg_buffer.getvalue().decode('utf-8') def add_logo(self, qr_img, logo_path, logo_size_ratio=0.2): """Add logo to QR code""" try: logo = Image.open(logo_path) # Calculate logo size qr_width, qr_height = qr_img.size logo_size = int(min(qr_width, qr_height) * logo_size_ratio) # Resize logo logo = logo.resize((logo_size, logo_size), Image.Resampling.LANCZOS) # Create a white background for the logo logo_bg = Image.new('RGB', (logo_size + 20, logo_size + 20), 'white') logo_bg.paste(logo, (10, 10)) # Calculate position to center the logo logo_pos = ( (qr_width - logo_bg.width) // 2, (qr_height - logo_bg.height) // 2 ) # Paste logo onto QR code qr_img.paste(logo_bg, logo_pos) return qr_img except Exception as e: print(f"Error adding logo: {e}") return qr_img