import os import io import base64 import json import uuid from datetime import datetime from PIL import Image, ImageDraw import qrcode from qrcode.image.styledpil import StyledPilImage from qrcode.image.styles.moduledrawers import RoundedModuleDrawer, CircleModuleDrawer, SquareModuleDrawer from qrcode.image.styles.colorfills import SolidFillColorMask from flask import Flask, request, jsonify, send_file, render_template from flask_cors import CORS app = Flask(__name__) CORS(app) # Configuration UPLOAD_FOLDER = 'static/qr_codes' LOGOS_FOLDER = 'static/logos' os.makedirs(UPLOAD_FOLDER, exist_ok=True) os.makedirs(LOGOS_FOLDER, exist_ok=True) # In-memory storage for QR codes (in production, use a database) qr_codes_db = {} 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): """Generate QR code with custom settings""" if settings is None: settings = self.default_settings.copy() else: merged_settings = self.default_settings.copy() merged_settings.update(settings) settings = merged_settings # 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 module drawer based on style module_drawer = None if settings['style'] == 'rounded': module_drawer = RoundedModuleDrawer() elif settings['style'] == 'circle': module_drawer = CircleModuleDrawer() else: module_drawer = SquareModuleDrawer() # Create color mask color_mask = SolidFillColorMask( back_color=settings['background_color'], front_color=settings['foreground_color'] ) # Generate the image img = qr.make_image( image_factory=StyledPilImage, module_drawer=module_drawer, color_mask=color_mask ) return img 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 # Initialize QR code generator qr_generator = QRCodeGenerator() @app.route('/') def index(): """Serve the main page""" return render_template('index.html') @app.route('/api/generate', methods=['POST']) def generate_qr(): """Generate QR code API endpoint""" try: data = request.json # Extract QR code content qr_type = data.get('type', 'text') content = data.get('content', '') # Process content based on type if qr_type == 'url': qr_content = content if content.startswith(('http://', 'https://')) else f'https://{content}' elif qr_type == 'wifi': wifi_data = data.get('wifi', {}) qr_content = f"WIFI:T:{wifi_data.get('security', 'WPA')};S:{wifi_data.get('ssid', '')};P:{wifi_data.get('password', '')};H:{wifi_data.get('hidden', 'false')};;" elif qr_type == 'email': email_data = data.get('email', {}) qr_content = f"mailto:{email_data.get('email', '')}?subject={email_data.get('subject', '')}&body={email_data.get('body', '')}" elif qr_type == 'phone': qr_content = f"tel:{content}" elif qr_type == 'sms': sms_data = data.get('sms', {}) qr_content = f"smsto:{sms_data.get('phone', '')}:{sms_data.get('message', '')}" elif qr_type == 'vcard': vcard_data = data.get('vcard', {}) qr_content = f"""BEGIN:VCARD VERSION:3.0 FN:{vcard_data.get('name', '')} ORG:{vcard_data.get('organization', '')} TEL:{vcard_data.get('phone', '')} EMAIL:{vcard_data.get('email', '')} URL:{vcard_data.get('website', '')} END:VCARD""" else: # text qr_content = content # Extract styling options settings = { 'size': data.get('size', 10), 'border': data.get('border', 4), 'foreground_color': data.get('foreground_color', '#000000'), 'background_color': data.get('background_color', '#FFFFFF'), 'style': data.get('style', 'square') } # Generate QR code qr_img = qr_generator.generate_qr_code(qr_content, settings) # Add logo if provided logo_path = data.get('logo_path') if logo_path and os.path.exists(logo_path): qr_img = qr_generator.add_logo(qr_img, logo_path) # Convert to base64 img_buffer = io.BytesIO() qr_img.save(img_buffer, format='PNG') img_buffer.seek(0) img_base64 = base64.b64encode(img_buffer.getvalue()).decode() # Save QR code record qr_id = str(uuid.uuid4()) qr_record = { 'id': qr_id, 'type': qr_type, 'content': qr_content, 'settings': settings, 'created_at': datetime.now().isoformat(), 'image_data': img_base64 } qr_codes_db[qr_id] = qr_record # Save image file img_path = os.path.join(UPLOAD_FOLDER, f'{qr_id}.png') qr_img.save(img_path) return jsonify({ 'success': True, 'qr_id': qr_id, 'image_data': f'data:image/png;base64,{img_base64}', 'download_url': f'/api/download/{qr_id}' }) except Exception as e: return jsonify({'success': False, 'error': str(e)}), 500 @app.route('/api/download/') def download_qr(qr_id): """Download QR code""" try: img_path = os.path.join(UPLOAD_FOLDER, f'{qr_id}.png') if os.path.exists(img_path): return send_file(img_path, as_attachment=True, download_name=f'qr_code_{qr_id}.png') else: return jsonify({'error': 'QR code not found'}), 404 except Exception as e: return jsonify({'error': str(e)}), 500 @app.route('/api/qr_codes') def list_qr_codes(): """List all generated QR codes""" qr_list = [] for qr_id, qr_data in qr_codes_db.items(): qr_list.append({ 'id': qr_id, 'type': qr_data['type'], 'created_at': qr_data['created_at'], 'preview': f'data:image/png;base64,{qr_data["image_data"]}' }) return jsonify(qr_list) @app.route('/api/qr_codes/') def get_qr_code(qr_id): """Get specific QR code details""" if qr_id in qr_codes_db: return jsonify(qr_codes_db[qr_id]) else: return jsonify({'error': 'QR code not found'}), 404 @app.route('/api/qr_codes/', methods=['DELETE']) def delete_qr_code(qr_id): """Delete QR code""" try: if qr_id in qr_codes_db: # Remove from database del qr_codes_db[qr_id] # Remove image file img_path = os.path.join(UPLOAD_FOLDER, f'{qr_id}.png') if os.path.exists(img_path): os.remove(img_path) return jsonify({'success': True}) else: return jsonify({'error': 'QR code not found'}), 404 except Exception as e: return jsonify({'error': str(e)}), 500 @app.route('/api/upload_logo', methods=['POST']) def upload_logo(): """Upload logo for QR code""" try: if 'logo' not in request.files: return jsonify({'error': 'No logo file provided'}), 400 file = request.files['logo'] if file.filename == '': return jsonify({'error': 'No file selected'}), 400 # Save logo logo_id = str(uuid.uuid4()) logo_extension = file.filename.rsplit('.', 1)[1].lower() logo_filename = f'{logo_id}.{logo_extension}' logo_path = os.path.join(LOGOS_FOLDER, logo_filename) file.save(logo_path) return jsonify({ 'success': True, 'logo_path': logo_path, 'logo_id': logo_id }) except Exception as e: return jsonify({'error': str(e)}), 500 if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000)