import os import io import base64 import subprocess import re import platform from flask import Flask, render_template, request, jsonify, send_file import segno from segno import helpers from PIL import Image app = Flask(__name__) app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB max upload def get_current_wifi_ssid(): """ Attempt to get the current connected WiFi SSID. Works primarily on macOS for local development. Returns None if detection fails or running in cloud. """ try: system = platform.system() if system == 'Darwin': # macOS process = subprocess.Popen( ['/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport', '-I'], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) out, err = process.communicate() if process.returncode == 0: output = out.decode('utf-8') match = re.search(r' SSID: (.+)', output) if match: return match.group(1).strip() elif system == 'Linux': # Basic attempt for Linux (might work if nmcli is installed and has permissions) # Unlikely to work in Docker/HF Spaces without host networking pass except Exception as e: print(f"WiFi detection failed: {e}") return None def hex_to_rgb(hex_color): hex_color = hex_color.lstrip('#') return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4)) @app.route('/') def index(): default_ssid = get_current_wifi_ssid() or '' return render_template('index.html', default_ssid=default_ssid) @app.route('/api/generate', methods=['POST']) def generate_qr(): try: data = request.form qr_type = data.get('type', 'text') content = data.get('content', '') fg_color = data.get('fg_color', '#000000') bg_color = data.get('bg_color', '#ffffff') scale = int(data.get('scale', 10)) border = int(data.get('border', 4)) # Handle colors (Segno expects hex or RGB tuple, but let's be safe) # Segno handles hex strings well. qr = None # 1. Generate QR Object if qr_type == 'wifi': ssid = data.get('wifi_ssid') password = data.get('wifi_password') security = data.get('wifi_security', 'WPA') hidden = data.get('wifi_hidden') == 'true' qr = helpers.make_wifi(ssid=ssid, password=password, security=security, hidden=hidden) elif qr_type == 'vcard': name = data.get('vcard_name') displayname = data.get('vcard_displayname') email = data.get('vcard_email') phone = data.get('vcard_phone') url = data.get('vcard_url') # Segno make_vcard is powerful qr = helpers.make_vcard(name=name, displayname=displayname, email=email, phone=phone, url=url) else: # Default text/url if not content: return jsonify({'error': '内容不能为空'}), 400 qr = segno.make(content, error='h') # High error correction for logos # 2. Convert to PIL Image out = io.BytesIO() qr.save(out, kind='png', scale=scale, border=border, dark=fg_color, light=bg_color) out.seek(0) img = Image.open(out).convert("RGBA") # 3. Handle Logo logo_file = request.files.get('logo') if logo_file: logo = Image.open(logo_file).convert("RGBA") # Calculate logo size (e.g., 20% of QR width) qr_width, qr_height = img.size logo_max_size = int(qr_width * 0.25) # 25% coverage max # Resize logo maintaining aspect ratio logo.thumbnail((logo_max_size, logo_max_size), Image.Resampling.LANCZOS) # Position centered logo_pos = ((qr_width - logo.size[0]) // 2, (qr_height - logo.size[1]) // 2) # Paste logo (with transparency support) # Create a white background for logo if needed or just paste # Usually better to have a small white border around logo for readability # Let's create a white backing for the logo logo_bg_size = (logo.size[0] + 4, logo.size[1] + 4) # 4px padding logo_bg = Image.new('RGBA', logo_bg_size, bg_color) logo_bg_pos = (logo_pos[0] - 2, logo_pos[1] - 2) img.paste(logo_bg, logo_bg_pos, logo_bg) # Paste white square img.paste(logo, logo_pos, logo) # Paste logo # 4. Return as Base64 final_out = io.BytesIO() img.save(final_out, format='PNG') final_out.seek(0) b64_data = base64.b64encode(final_out.getvalue()).decode() return jsonify({ 'image': f'data:image/png;base64,{b64_data}', 'filename': 'qrcode.png' }) except Exception as e: print(f"Error: {e}") return jsonify({'error': str(e)}), 500 if __name__ == '__main__': app.run(host='0.0.0.0', port=7860, debug=True)