Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import qrcode | |
| import random | |
| import os | |
| from datetime import datetime | |
| from PIL import Image, ImageDraw | |
| from math import cos, sin, radians | |
| def create_border_decoration(qr_image, decoration_style="Flowers"): | |
| # Convert QR image to RGB mode first | |
| qr_image = qr_image.convert('RGB') | |
| # Get the size of the QR code image | |
| width, height = qr_image.size | |
| # ํจ๋ฉ์ ๋ ์๊ฒ ์กฐ์ | |
| padding = 20 # ํจ๋ฉ์ 30์์ 20์ผ๋ก ์ค์ | |
| new_width = width + (padding * 2) | |
| new_height = height + (padding * 2) | |
| # Create new image with white background | |
| decorated_image = Image.new('RGB', (new_width, new_height), 'white') | |
| # Paste QR code in center | |
| decorated_image.paste(qr_image, (padding, padding)) | |
| # Get draw object | |
| draw = ImageDraw.Draw(decorated_image) | |
| # ์ฅ์ ํฌ๊ธฐ ์ค์ - ๊ฐ๊ฒฉ์ ๋ ์ข๊ฒ | |
| deco_size = 8 # ์ฅ์ ํฌ๊ธฐ๋ฅผ 12์์ 8๋ก ์ค์ | |
| gap = deco_size * 1.5 # ๊ฐ๊ฒฉ์ 2๋ฐฐ์์ 1.5๋ฐฐ๋ก ์ค์ | |
| # ํ ๋๋ฆฌ๋ฅผ ๋ฐ๋ผ ์ ๋ค์ ์์น ๊ณ์ฐ | |
| border_points = [] | |
| # ์๋จ ํ ๋๋ฆฌ | |
| for x in range(padding//2, new_width - padding//2, int(gap)): | |
| border_points.append((x, padding//2)) | |
| # ์ฐ์ธก ํ ๋๋ฆฌ | |
| for y in range(padding//2, new_height - padding//2, int(gap)): | |
| border_points.append((new_width - padding//2, y)) | |
| # ํ๋จ ํ ๋๋ฆฌ | |
| for x in range(new_width - padding//2, padding//2, -int(gap)): | |
| border_points.append((x, new_height - padding//2)) | |
| # ์ข์ธก ํ ๋๋ฆฌ | |
| for y in range(new_height - padding//2, padding//2, -int(gap)): | |
| border_points.append((padding//2, y)) | |
| # ๊ฐ ์คํ์ผ์ ๋ฐ๋ฅธ ์ฅ์ ๊ทธ๋ฆฌ๊ธฐ | |
| for x, y in border_points: | |
| if decoration_style == "Flowers": # ๊ฝ ํจํด | |
| # ๊ฝ์ | |
| for angle in range(0, 360, 45): | |
| x1 = x + deco_size * cos(radians(angle)) | |
| y1 = y + deco_size * sin(radians(angle)) | |
| draw.ellipse([x1-4, y1-4, x1+4, y1+4], fill='pink') | |
| # ๊ฝ ์ค์ฌ | |
| draw.ellipse([x-3, y-3, x+3, y+3], fill='yellow') | |
| elif decoration_style == "Hearts": # ํํธ ํจํด | |
| # ์์ ํํธ๋ค์ ์ฐ์์ผ๋ก ๊ทธ๋ฆฌ๊ธฐ | |
| heart_size = 6 | |
| draw.ellipse([x-heart_size, y-heart_size, x, y], fill='red') | |
| draw.ellipse([x, y-heart_size, x+heart_size, y], fill='red') | |
| draw.polygon([(x-heart_size, y), (x+heart_size, y), (x, y+heart_size)], fill='red') | |
| elif decoration_style == "Waves": # ์จ์ด๋ธ ํจํด | |
| wave_size = 10 | |
| draw.arc([x-wave_size, y-wave_size//2, x+wave_size, y+wave_size//2], | |
| 0, 180, fill='lightblue', width=2) | |
| draw.arc([x-wave_size, y, x+wave_size, y+wave_size], | |
| 0, 180, fill='blue', width=2) | |
| elif decoration_style == "Leaves": # ์ ํจํด | |
| leaf_size = 8 | |
| # ๋ฉ์ธ ์ | |
| draw.ellipse([x-leaf_size, y-leaf_size//2, x+leaf_size, y+leaf_size//2], | |
| fill='lightgreen') | |
| # ์์ ์ | |
| draw.ellipse([x-leaf_size//2, y-leaf_size, x+leaf_size//2, y+leaf_size], | |
| fill='darkgreen') | |
| elif decoration_style == "Stars": # ๋ณ ํจํด | |
| star_size = 6 | |
| points = [] | |
| for i in range(5): | |
| angle = i * 72 | |
| # ์ธ๊ณฝ ์ | |
| x1 = x + star_size * cos(radians(angle)) | |
| y1 = y + star_size * sin(radians(angle)) | |
| points.append((x1, y1)) | |
| # ๋ด๋ถ ์ | |
| x2 = x + (star_size/2) * cos(radians(angle + 36)) | |
| y2 = y + (star_size/2) * sin(radians(angle + 36)) | |
| points.append((x2, y2)) | |
| draw.polygon(points, fill='gold') | |
| elif decoration_style == "Chains": # ์ฒด์ธ ํจํด | |
| chain_size = 8 | |
| draw.ellipse([x-chain_size, y-chain_size//2, x+chain_size, y+chain_size//2], | |
| outline='gray', width=2) | |
| elif decoration_style == "Bubbles": # ๋ฒ๋ธ ํจํด | |
| bubble_sizes = [6, 4, 2] | |
| for size in bubble_sizes: | |
| draw.ellipse([x-size, y-size, x+size, y+size], | |
| outline='skyblue', width=1) | |
| elif decoration_style == "Vines": # ๋ฉ๊ตด ํจํด | |
| vine_size = 10 | |
| # ๋ฉ์ธ ๋ฉ๊ตด | |
| draw.arc([x-vine_size, y-vine_size, x+vine_size, y+vine_size], | |
| 0, 180, fill='green', width=2) | |
| # ์์ ์ | |
| draw.ellipse([x-3, y-3, x+3, y+3], fill='lightgreen') | |
| elif decoration_style == "Diamonds": # ๋ค์ด์๋ชฌ๋ ํจํด | |
| diamond_size = 6 | |
| points = [ | |
| (x, y-diamond_size), # ์๋จ | |
| (x+diamond_size, y), # ์ฐ์ธก | |
| (x, y+diamond_size), # ํ๋จ | |
| (x-diamond_size, y) # ์ข์ธก | |
| ] | |
| draw.polygon(points, outline='purple', width=1) | |
| elif decoration_style == "Lace": # ๋ ์ด์ค ํจํด | |
| lace_size = 8 | |
| # ๋ ์ด์ค ์ํ ํจํด | |
| draw.arc([x-lace_size, y-lace_size, x+lace_size, y+lace_size], | |
| 0, 180, fill='gray', width=1) | |
| draw.arc([x-lace_size//2, y-lace_size//2, x+lace_size//2, y+lace_size//2], | |
| 180, 360, fill='gray', width=1) | |
| return decorated_image | |
| def rgba_to_rgb(rgba_color): | |
| """Convert RGBA color string to RGB hex color""" | |
| if rgba_color.startswith('rgba'): | |
| # Extract numbers from rgba string | |
| values = rgba_color.strip('rgba()').split(',') | |
| r = int(float(values[0])) | |
| g = int(float(values[1])) | |
| b = int(float(values[2])) | |
| return f'#{r:02x}{g:02x}{b:02x}' | |
| return rgba_color | |
| def create_qr(content, qr_type, fill_color, back_color, box_size, border_size, error_correction, border_decoration="No Decoration"): | |
| # Convert RGBA colors to RGB | |
| fill_color = rgba_to_rgb(fill_color) | |
| back_color = rgba_to_rgb(back_color) | |
| # QR ์ฝ๋ ๋ฐ์ดํฐ ํฌ๋งทํ | |
| formatted_data = format_data(content, qr_type) | |
| # ์๋ฌ ์์ ๋ ๋ฒจ ์ค์ | |
| error_levels = { | |
| "Low (7%)": qrcode.constants.ERROR_CORRECT_L, | |
| "Medium (15%)": qrcode.constants.ERROR_CORRECT_M, | |
| "Quartile (25%)": qrcode.constants.ERROR_CORRECT_Q, | |
| "High (30%)": qrcode.constants.ERROR_CORRECT_H | |
| } | |
| # QR ์ฝ๋ ์์ฑ | |
| qr = qrcode.QRCode( | |
| version=1, | |
| error_correction=error_levels[error_correction], | |
| box_size=box_size, | |
| border=border_size, | |
| ) | |
| qr.add_data(formatted_data) | |
| qr.make(fit=True) | |
| # QR ์ด๋ฏธ์ง ์์ฑ | |
| qr_img = qr.make_image(fill_color=fill_color, back_color=back_color) | |
| # Add border decoration if specified and not "No Decoration" | |
| if border_decoration != "No Decoration": | |
| qr_img = create_border_decoration(qr_img, border_decoration) | |
| # ํ์ผ ์ ์ฅ | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| random_id = random.randint(1000, 9999) | |
| filename = f"qrfile/qr_{timestamp}_{random_id}.png" | |
| # ๋๋ ํ ๋ฆฌ ํ์ธ ๋ฐ ์์ฑ | |
| os.makedirs("qrfile", exist_ok=True) | |
| # ์ด๋ฏธ์ง ์ ์ฅ | |
| qr_img.save(filename) | |
| cleanup_old_files("qrfile/", max_files=100) | |
| return filename, formatted_data | |
| # ๋ฐ์ดํฐ ํฌ๋งทํ ํจ์ | |
| def format_data(content, qr_type): | |
| if not content: | |
| return "" | |
| format_rules = { | |
| "URL": lambda x: f"https://{x}" if not x.startswith(('http://', 'https://')) else x, | |
| "Email": lambda x: f"mailto:{x}", | |
| "Phone": lambda x: f"tel:{x}", | |
| "SMS": lambda x: f"sms:{x}", | |
| "WhatsApp": lambda x: f"whatsapp://send?text={x}", | |
| "Location": lambda x: f"geo:{x}", | |
| "Wi-Fi": lambda x: f"WIFI:S:{x};;", | |
| "Text": lambda x: x, | |
| "vCard": lambda x: f"BEGIN:VCARD\nVERSION:3.0\n{x}\nEND:VCARD" | |
| } | |
| return format_rules[qr_type](content.strip()) | |
| # ํ์ผ ์ ๋ฆฌ ํจ์ | |
| def cleanup_old_files(directory, max_files): | |
| files = [f for f in os.listdir(directory) if f.endswith('.png')] | |
| if len(files) > max_files: | |
| files.sort(key=lambda x: os.path.getctime(os.path.join(directory, x))) | |
| for f in files[:-max_files]: | |
| try: | |
| os.remove(os.path.join(directory, f)) | |
| except: | |
| continue | |
| def format_example_text(qr_type): | |
| examples = { | |
| "URL": "โข Direct URL: https://example.com\nโข Without https: example.com", | |
| "Email": "โข Basic: [email protected]\nโข With subject: [email protected]?subject=Hello", | |
| "Phone": "โข International: +1234567890\nโข Local: 01012345678", | |
| "SMS": "โข Basic: +1234567890\nโข With message: +1234567890?body=Hello", | |
| "WhatsApp": "โข Message: Hello World!\nโข With number: +1234567890:Hello", | |
| "Location": "โข Coordinates: 37.7749,-122.4194\nโข With zoom: 37.7749,-122.4194,15z", | |
| "Wi-Fi": "โข Network name only: MyWiFiNetwork\nโข With password: WIFI:S:MyNetwork;P:password;;", | |
| "Text": "โข Simple text: Hello World!\nโข Multiple lines: Line 1\\nLine 2", | |
| "vCard": "โข Basic:\nFN:John Doe\nTEL:+1234567890\nEMAIL:[email protected]\nโข Extended:\nFN:John Doe\nTEL:+1234567890\nEMAIL:[email protected]\nADR:;;123 Street;City;State;12345;Country" | |
| } | |
| return examples.get(qr_type, "Enter your content here...") | |
| def create_interface(): | |
| theme = gr.themes.Soft( | |
| primary_hue="blue", | |
| secondary_hue="indigo", | |
| ).set( | |
| body_background_fill="*neutral_50", | |
| block_background_fill="*neutral_100", | |
| button_primary_background_fill="*primary_500", | |
| ) | |
| with gr.Blocks(theme=theme, title="QR Canvas") as demo: | |
| gr.Markdown( | |
| """ | |
| # ๐ฏ QR CANVAS+ | |
| Create customized QR codes for various purposes with professional styling options. | |
| """ | |
| ) | |
| gr.HTML("""<a href="https://visitorbadge.io/status?path=https%3A%2F%2Fginipick-QR-Canvas.hf.space"> | |
| <img src="https://api.visitorbadge.io/api/visitors?path=https%3A%2F%2Fginipick-QR-Canvas.hf.space&countColor=%23263759" /> | |
| </a>""") | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| qr_type = gr.Dropdown( | |
| choices=["URL", "Email", "Phone", "SMS", "WhatsApp", "Location", "Wi-Fi", "Text", "vCard"], | |
| value="URL", | |
| label="QR Code Type" | |
| ) | |
| content = gr.Textbox( | |
| label="Content", | |
| placeholder="Enter your content here...", | |
| lines=3 | |
| ) | |
| example_format = gr.Textbox( | |
| value=format_example_text("URL"), | |
| label="Format Examples", | |
| interactive=False, | |
| lines=6 | |
| ) | |
| with gr.Row(): | |
| fill_color = gr.ColorPicker( | |
| label="QR Code Color", | |
| value="#000000" | |
| ) | |
| back_color = gr.ColorPicker( | |
| label="Background Color", | |
| value="#FFFFFF" | |
| ) | |
| with gr.Row(): | |
| box_size = gr.Slider( | |
| minimum=1, | |
| maximum=30, # ์ต๋๊ฐ์ 20์์ 30์ผ๋ก ์ฆ๊ฐ | |
| value=15, # ๊ธฐ๋ณธ๊ฐ์ 10์์ 15๋ก ์ฆ๊ฐ | |
| step=1, | |
| label="QR Code Size" | |
| ) | |
| border_size = gr.Slider( | |
| minimum=0, | |
| maximum=5, # ์ต๋๊ฐ์ 10์์ 5๋ก ๊ฐ์ | |
| value=2, # ๊ธฐ๋ณธ๊ฐ์ 4์์ 2๋ก ๊ฐ์ | |
| step=1, | |
| label="Border Size" | |
| ) | |
| error_correction = gr.Dropdown( | |
| choices=[ | |
| "Low (7%)", | |
| "Medium (15%)", | |
| "Quartile (25%)", | |
| "High (30%)" | |
| ], | |
| value="Medium (15%)", | |
| label="Error Correction Level" | |
| ) | |
| border_decoration = gr.Dropdown( | |
| choices=[ | |
| "No Decoration", # ๋ช ์์ ์ธ "์ฅ์ ์์" ์ต์ | |
| "Flowers", | |
| "Hearts", | |
| "Waves", | |
| "Leaves", | |
| "Stars", | |
| "Chains", | |
| "Bubbles", | |
| "Vines", | |
| "Diamonds", | |
| "Lace" | |
| ], | |
| value="No Decoration", # ๊ธฐ๋ณธ๊ฐ์ผ๋ก "No Decoration" ์ค์ | |
| label="Border Decoration Style" | |
| ) | |
| generate_btn = gr.Button( | |
| "Generate QR Code", | |
| variant="primary" | |
| ) | |
| with gr.Column(scale=1): | |
| output_image = gr.Image( | |
| label="Generated QR Code", | |
| type="filepath" | |
| ) | |
| output_data = gr.Textbox( | |
| label="Formatted Data", | |
| interactive=False | |
| ) | |
| def update_example(qr_type): | |
| return format_example_text(qr_type) | |
| qr_type.change( | |
| fn=update_example, | |
| inputs=[qr_type], | |
| outputs=example_format | |
| ) | |
| generate_btn.click( | |
| fn=create_qr, | |
| inputs=[ | |
| content, | |
| qr_type, | |
| fill_color, | |
| back_color, | |
| box_size, | |
| border_size, | |
| error_correction, | |
| border_decoration | |
| ], | |
| outputs=[output_image, output_data] | |
| ) | |
| gr.Markdown( | |
| """ | |
| ### ๐ Instructions | |
| 1. Select the QR code type from the dropdown menu | |
| 2. Enter your content following the format examples shown | |
| 3. Customize the appearance using the color pickers and sliders | |
| 4. Click 'Generate QR Code' to create your custom QR code | |
| ### ๐ก Tips | |
| - Use higher error correction levels for better scan reliability | |
| - Ensure sufficient contrast between QR code and background colors | |
| - Keep the content concise for better readability | |
| - Follow the format examples for best results | |
| """ | |
| ) | |
| return demo | |
| if __name__ == "__main__": | |
| try: | |
| os.makedirs("qrfile", exist_ok=True) | |
| demo = create_interface() | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=True, | |
| debug=True | |
| ) | |
| except Exception as e: | |
| print(f"Error starting the application: {e}") |