Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import qrcode | |
| from PIL import Image, ImageDraw, ImageFont | |
| import io | |
| import base64 | |
| # Page configuration | |
| st.set_page_config( | |
| page_title="QR Code Generator", | |
| page_icon="π±", | |
| layout="wide", | |
| initial_sidebar_state="expanded" | |
| ) | |
| # Custom CSS for beautiful styling | |
| st.markdown(""" | |
| <style> | |
| .main-header { | |
| text-align: center; | |
| padding: 2rem 0; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| border-radius: 10px; | |
| margin-bottom: 2rem; | |
| } | |
| .feature-box { | |
| background: #f8f9fa; | |
| padding: 1.5rem; | |
| border-radius: 10px; | |
| border-left: 4px solid #667eea; | |
| margin: 1rem 0; | |
| } | |
| .download-section { | |
| background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%); | |
| padding: 2rem; | |
| border-radius: 15px; | |
| text-align: center; | |
| margin: 2rem 0; | |
| } | |
| .sidebar-section { | |
| background: #ffffff; | |
| padding: 1rem; | |
| border-radius: 10px; | |
| margin: 1rem 0; | |
| box-shadow: 0 2px 4px rgba(0,0,0,0.1); | |
| } | |
| .stDownloadButton > button { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| border: none; | |
| border-radius: 10px; | |
| padding: 0.5rem 2rem; | |
| font-weight: bold; | |
| width: 100%; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| def hex_to_rgb(hex_color): | |
| """Convert hex color to RGB tuple""" | |
| hex_color = hex_color.lstrip('#') | |
| return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4)) | |
| def create_gradient_image(size, start_color, end_color, direction='horizontal'): | |
| """Create a gradient image""" | |
| image = Image.new('RGB', size) | |
| draw = ImageDraw.Draw(image) | |
| if direction == 'horizontal': | |
| for x in range(size[0]): | |
| ratio = x / size[0] | |
| r = int(start_color[0] * (1 - ratio) + end_color[0] * ratio) | |
| g = int(start_color[1] * (1 - ratio) + end_color[1] * ratio) | |
| b = int(start_color[2] * (1 - ratio) + end_color[2] * ratio) | |
| draw.line([(x, 0), (x, size[1])], fill=(r, g, b)) | |
| else: # vertical | |
| for y in range(size[1]): | |
| ratio = y / size[1] | |
| r = int(start_color[0] * (1 - ratio) + end_color[0] * ratio) | |
| g = int(start_color[1] * (1 - ratio) + end_color[1] * ratio) | |
| b = int(start_color[2] * (1 - ratio) + end_color[2] * ratio) | |
| draw.line([(0, y), (size[0], y)], fill=(r, g, b)) | |
| return image | |
| def create_rounded_qr(qr_img, corner_radius=20): | |
| """Create rounded corners for QR code""" | |
| # Create mask for rounded corners | |
| size = qr_img.size | |
| mask = Image.new('L', size, 0) | |
| draw = ImageDraw.Draw(mask) | |
| draw.rounded_rectangle([(0, 0), size], corner_radius, fill=255) | |
| # Apply mask | |
| qr_rounded = Image.new('RGBA', size, (255, 255, 255, 0)) | |
| qr_rounded.paste(qr_img, (0, 0)) | |
| qr_rounded.putalpha(mask) | |
| return qr_rounded | |
| def create_qr_code(data, fill_color, back_color, border, box_size, error_correction, style_type, gradient_end_color=None): | |
| """Generate QR code with custom styling""" | |
| # Error correction levels | |
| error_levels = { | |
| 'L (~7%)': qrcode.constants.ERROR_CORRECT_L, | |
| 'M (~15%)': qrcode.constants.ERROR_CORRECT_M, | |
| 'Q (~25%)': qrcode.constants.ERROR_CORRECT_Q, | |
| 'H (~30%)': qrcode.constants.ERROR_CORRECT_H | |
| } | |
| # Create QR code instance | |
| qr = qrcode.QRCode( | |
| version=1, | |
| error_correction=error_levels[error_correction], | |
| box_size=box_size, | |
| border=border, | |
| ) | |
| qr.add_data(data) | |
| qr.make(fit=True) | |
| # Generate base QR code | |
| if style_type == "Gradient" and gradient_end_color: | |
| # Create gradient background | |
| img = qr.make_image(fill_color='black', back_color='white') | |
| # Create gradient | |
| start_rgb = hex_to_rgb(fill_color) | |
| end_rgb = hex_to_rgb(gradient_end_color) | |
| gradient = create_gradient_image(img.size, start_rgb, end_rgb, 'horizontal') | |
| # Apply gradient to QR code | |
| img_array = img.load() | |
| gradient_array = gradient.load() | |
| for x in range(img.size[0]): | |
| for y in range(img.size[1]): | |
| if img_array[x, y] == 0: # Black pixel (QR code data) | |
| img_array[x, y] = gradient_array[x, y] | |
| else: # White pixel (background) | |
| img_array[x, y] = hex_to_rgb(back_color) | |
| else: | |
| img = qr.make_image(fill_color=fill_color, back_color=back_color) | |
| # Apply style modifications | |
| if style_type == "Rounded": | |
| img = create_rounded_qr(img, corner_radius=box_size*2) | |
| elif style_type == "With Logo Space": | |
| # Create space in center for logo | |
| draw = ImageDraw.Draw(img) | |
| center_x, center_y = img.size[0] // 2, img.size[1] // 2 | |
| logo_size = min(img.size) // 6 | |
| draw.rectangle([ | |
| center_x - logo_size//2, center_y - logo_size//2, | |
| center_x + logo_size//2, center_y + logo_size//2 | |
| ], fill=back_color, outline=fill_color, width=2) | |
| return img | |
| def get_qr_data_by_type(content_type): | |
| """Get QR data based on content type""" | |
| if content_type == "Text": | |
| return st.text_area("Enter your text:", height=100, placeholder="Hello World!") | |
| elif content_type == "URL": | |
| url = st.text_input("Enter URL:", placeholder="https://example.com") | |
| if url and not url.startswith(('http://', 'https://')): | |
| url = 'https://' + url | |
| return url | |
| elif content_type == "Email": | |
| email = st.text_input("Email address:", placeholder="contact@example.com") | |
| subject = st.text_input("Subject (optional):") | |
| body = st.text_area("Message (optional):", height=80) | |
| if email: | |
| params = [] | |
| if subject: | |
| params.append(f"subject={subject}") | |
| if body: | |
| params.append(f"body={body}") | |
| return f"mailto:{email}{'?' + '&'.join(params) if params else ''}" | |
| return "" | |
| elif content_type == "Phone": | |
| phone = st.text_input("Phone number:", placeholder="+1234567890") | |
| return f"tel:{phone}" if phone else "" | |
| elif content_type == "SMS": | |
| phone = st.text_input("Phone number:", placeholder="+1234567890") | |
| message = st.text_area("Message:", height=80, placeholder="Hello!") | |
| if phone: | |
| return f"sms:{phone}{'?body=' + message if message else ''}" | |
| return "" | |
| elif content_type == "WiFi": | |
| ssid = st.text_input("Network Name (SSID):", placeholder="MyWiFi") | |
| password = st.text_input("Password:", type="password") | |
| security = st.selectbox("Security Type", ["WPA", "WEP", "nopass"]) | |
| hidden = st.checkbox("Hidden Network") | |
| if ssid: | |
| return f"WIFI:T:{security};S:{ssid};P:{password};H:{'true' if hidden else 'false'};;" | |
| return "" | |
| elif content_type == "vCard": | |
| name = st.text_input("Full Name:", placeholder="John Doe") | |
| phone = st.text_input("Phone:", placeholder="+1234567890") | |
| email = st.text_input("Email:", placeholder="john@example.com") | |
| organization = st.text_input("Organization (optional):", placeholder="Company Inc.") | |
| if name: | |
| vcard = f"BEGIN:VCARD\nVERSION:3.0\nFN:{name}\n" | |
| if phone: | |
| vcard += f"TEL:{phone}\n" | |
| if email: | |
| vcard += f"EMAIL:{email}\n" | |
| if organization: | |
| vcard += f"ORG:{organization}\n" | |
| vcard += "END:VCARD" | |
| return vcard | |
| return "" | |
| # Main header | |
| st.markdown(""" | |
| <div class="main-header"> | |
| <h1>π¨ Beautiful QR Code Generator</h1> | |
| <p>Create stunning, customizable QR codes with advanced styling options</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Sidebar for customization | |
| with st.sidebar: | |
| st.markdown("## ποΈ Customization Panel") | |
| # QR Code Content | |
| st.markdown('<div class="sidebar-section">', unsafe_allow_html=True) | |
| st.markdown("### π Content") | |
| content_type = st.selectbox( | |
| "Content Type", | |
| ["Text", "URL", "Email", "Phone", "SMS", "WiFi", "vCard"] | |
| ) | |
| qr_data = get_qr_data_by_type(content_type) | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| # Style Settings | |
| st.markdown('<div class="sidebar-section">', unsafe_allow_html=True) | |
| st.markdown("### π¨ Style Settings") | |
| style_type = st.selectbox( | |
| "QR Style", | |
| ["Standard", "Rounded", "Gradient", "With Logo Space"] | |
| ) | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| fill_color = st.color_picker("Foreground Color", "#000000") | |
| with col2: | |
| back_color = st.color_picker("Background Color", "#FFFFFF") | |
| gradient_end_color = None | |
| if style_type == "Gradient": | |
| gradient_end_color = st.color_picker("Gradient End Color", "#333333") | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| # Advanced Settings | |
| st.markdown('<div class="sidebar-section">', unsafe_allow_html=True) | |
| st.markdown("### βοΈ Advanced Settings") | |
| box_size = st.slider("Module Size", 5, 20, 10, help="Size of each QR code square") | |
| border = st.slider("Border Width", 1, 10, 4, help="White border around QR code") | |
| error_correction = st.selectbox( | |
| "Error Correction Level", | |
| ["L (~7%)", "M (~15%)", "Q (~25%)", "H (~30%)"], | |
| index=1, | |
| help="Higher levels = more damage resistance but larger code" | |
| ) | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| # Main content area | |
| col1, col2 = st.columns([2, 1]) | |
| with col1: | |
| if qr_data: | |
| try: | |
| # Generate QR code | |
| with st.spinner("π¨ Generating your beautiful QR code..."): | |
| qr_img = create_qr_code( | |
| qr_data, fill_color, back_color, border, | |
| box_size, error_correction, style_type, gradient_end_color | |
| ) | |
| # Display QR code | |
| st.markdown("### π± Your QR Code") | |
| st.image(qr_img, caption="Generated QR Code", use_container_width=True) | |
| # Convert to bytes for download | |
| img_buffer = io.BytesIO() | |
| qr_img.save(img_buffer, format="PNG") | |
| img_bytes = img_buffer.getvalue() | |
| # Download section | |
| st.markdown(""" | |
| <div class="download-section"> | |
| <h3>π Ready to Download!</h3> | |
| <p>Your QR code is ready. Click below to download it as PNG.</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Download button | |
| filename = f"qrcode_{content_type.lower()}_{style_type.lower().replace(' ', '_')}.png" | |
| st.download_button( | |
| label="π₯ Download QR Code", | |
| data=img_bytes, | |
| file_name=filename, | |
| mime="image/png", | |
| use_container_width=True | |
| ) | |
| # QR Code Info | |
| st.info(f""" | |
| **QR Code Details:** | |
| - Content Type: {content_type} | |
| - Style: {style_type} | |
| - Size: {qr_img.size[0]}x{qr_img.size[1]} pixels | |
| - Error Correction: {error_correction} | |
| """) | |
| except Exception as e: | |
| st.error(f"β Error generating QR code: {str(e)}") | |
| st.info("π‘ Try adjusting your content or settings") | |
| else: | |
| # Welcome message with example | |
| st.markdown(""" | |
| ### π Welcome to QR Code Generator! | |
| π **Get started by entering content in the sidebar** | |
| #### π What you can create: | |
| - **Text QR codes** for messages | |
| - **URL QR codes** for websites | |
| - **Contact QR codes** (vCard format) | |
| - **WiFi QR codes** for easy connection | |
| - **Email & SMS QR codes** | |
| #### π¨ Styling options: | |
| - Custom colors | |
| - Rounded corners | |
| - Gradient effects | |
| - Logo space preparation | |
| """) | |
| with col2: | |
| st.markdown("### β¨ Features") | |
| features = [ | |
| "π¨ Multiple visual styles", | |
| "π Custom colors & gradients", | |
| "π± Various content types", | |
| "βοΈ Advanced settings", | |
| "π₯ Instant PNG download", | |
| "π§ Error correction levels", | |
| "π vCard contact support", | |
| "πΆ WiFi QR codes" | |
| ] | |
| for feature in features: | |
| st.markdown(f'<div class="feature-box">{feature}</div>', unsafe_allow_html=True) | |
| st.markdown("### π‘ Pro Tips") | |
| st.success(""" | |
| **π― Best Practices:** | |
| - Use high contrast colors | |
| - Test with your phone camera | |
| - Higher error correction for outdoor use | |
| - Larger module size for distant scanning | |
| - Keep URLs short for simpler codes | |
| """) | |
| st.markdown("### π Error Correction Guide") | |
| st.info(""" | |
| - **L (7%)**: Good for clean environments | |
| - **M (15%)**: Standard recommendation | |
| - **Q (25%)**: Better for rough handling | |
| - **H (30%)**: Best for outdoor/damaged codes | |
| """) | |
| # Footer | |
| st.markdown("---") | |
| st.markdown(""" | |
| <div style="text-align: center; color: #666; padding: 2rem;"> | |
| <p>π Built with Streamlit | π Made for QR code enthusiasts</p> | |
| <p><small>π‘ Tip: Bookmark this page for quick QR code generation!</small></p> | |
| </div> | |
| """, unsafe_allow_html=True) |