Spaces:
Sleeping
Sleeping
| 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)) | |
| def index(): | |
| default_ssid = get_current_wifi_ssid() or '' | |
| return render_template('index.html', default_ssid=default_ssid) | |
| 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) | |