Files
qr-code-generator/app.py

286 lines
9.1 KiB
Python

"""
QR Code Generator - Streamlit Application
A web application for generating QR codes with optional logo overlay
and export in multiple formats and resolutions.
"""
import streamlit as st
from PIL import Image
import io
from utils.qr_generator import QRCodeGenerator
from utils.wifi_qr import WiFiQRCode
# Page configuration
st.set_page_config(
page_title="QR Code Generator",
page_icon="📱",
layout="centered",
initial_sidebar_state="expanded"
)
def main():
"""Main application function."""
st.title("QR Code Generator")
st.markdown("Generate professional QR codes with optional logo overlay")
# Sidebar configuration
with st.sidebar:
st.header("Configuration")
# Error correction level
error_correction = st.selectbox(
"Error Correction Level",
options=["L (7%)", "M (15%)", "Q (25%)", "H (30%)"],
index=3,
help="Higher levels allow more damage/obscurity. Use H (30%) for logos."
)
error_level = error_correction[0]
# QR code appearance
st.subheader("Appearance")
fill_color = st.color_picker("QR Code Color", "#000000")
back_color = st.color_picker("Background Color", "#FFFFFF")
# Export settings
st.subheader("Export Settings")
export_format = st.selectbox(
"Format",
options=["PNG", "JPEG", "SVG"],
help="SVG is vector format (scalable), PNG/JPEG are raster formats"
)
if export_format in ["PNG", "JPEG"]:
# Define resolution options
resolution_labels = {
500: "Low (500px)",
1000: "Medium (1000px)",
2000: "High (2000px)",
4000: "Ultra (4000px)"
}
target_size = st.select_slider(
"Resolution",
options=[500, 1000, 2000, 4000],
value=2000, # Default to High
format_func=lambda x: resolution_labels[x]
)
else:
svg_scale = st.slider(
"SVG Scale",
min_value=5,
max_value=20,
value=10,
help="Scale factor for SVG output"
)
# Main content area
st.divider()
# Mode selection
qr_mode = st.radio(
"QR Code Type",
options=["URL", "WiFi"],
horizontal=True,
help="Choose what type of QR code to generate"
)
st.divider()
# Content input based on mode
if qr_mode == "URL":
# URL input
url = st.text_input(
"Enter URL",
placeholder="https://example.com",
help="Enter the URL you want to encode in the QR code"
)
qr_content = url
else:
# WiFi input fields
st.subheader("WiFi Network Details")
col1, col2 = st.columns(2)
with col1:
wifi_ssid = st.text_input(
"Network Name (SSID)",
placeholder="MyWiFiNetwork",
help="The name of your WiFi network"
)
wifi_security = st.selectbox(
"Security Type",
options=["WPA/WPA2", "WEP", "None (Open)"],
help="WiFi security/encryption type"
)
with col2:
wifi_password = st.text_input(
"Password",
type="password",
placeholder="Enter WiFi password",
help="Leave empty for open networks"
)
wifi_hidden = st.checkbox(
"Hidden Network",
value=False,
help="Check if this is a hidden network"
)
# Map security display to QR code format
security_map = {
"WPA/WPA2": "WPA",
"WEP": "WEP",
"None (Open)": "nopass"
}
# Generate WiFi QR string
if wifi_ssid:
wifi_qr = WiFiQRCode(
ssid=wifi_ssid,
password=wifi_password if wifi_security != "None (Open)" else "",
security=security_map[wifi_security],
hidden=wifi_hidden
)
qr_content = wifi_qr.to_string()
else:
qr_content = ""
# Logo upload (optional)
st.subheader("Logo (Optional)")
logo_file = st.file_uploader(
"Upload logo image",
type=["png", "jpg", "jpeg"],
help="Upload a logo to place in the center of the QR code"
)
if logo_file:
logo_size_ratio = st.slider(
"Logo Size",
min_value=0.1,
max_value=0.4,
value=0.3,
step=0.05,
help="Logo size as ratio of QR code size"
)
# Generate button
if st.button("Generate QR Code", type="primary", use_container_width=True):
if not qr_content:
if qr_mode == "URL":
st.error("Please enter a URL")
else:
st.error("Please enter WiFi network name (SSID)")
return
try:
with st.spinner("Generating QR code..."):
# Initialize generator
generator = QRCodeGenerator(qr_content, error_level)
# Generate QR code
if export_format == "SVG":
# Generate SVG directly
svg_data = generator.generate_svg(scale=svg_scale)
# Display preview (SVG as image)
st.success("QR Code generated successfully!")
st.image(svg_data, caption="QR Code Preview")
# Download button
file_prefix = "wifi_qr" if qr_mode == "WiFi" else "url_qr"
st.download_button(
label=f"Download QR Code (SVG)",
data=svg_data,
file_name=f"{file_prefix}.svg",
mime="image/svg+xml",
use_container_width=True
)
else:
# Generate raster image (PNG/JPEG)
qr_image = generator.generate_qr_image(
box_size=20,
border=4,
fill_color=fill_color,
back_color=back_color
)
# Add logo if provided
if logo_file:
logo_image = Image.open(logo_file)
qr_image = generator.add_logo(
qr_image,
logo_image,
logo_size_ratio
)
# Resize to target resolution
qr_image = generator.resize_image(
qr_image,
(target_size, target_size)
)
# Export image
image_data = generator.export_image(
qr_image,
format=export_format,
quality=95
)
# Display preview
st.success("QR Code generated successfully!")
st.image(qr_image, caption="QR Code Preview")
# Download button
mime_types = {
"PNG": "image/png",
"JPEG": "image/jpeg"
}
file_prefix = "wifi_qr" if qr_mode == "WiFi" else "url_qr"
st.download_button(
label=f"Download QR Code ({export_format}, {target_size}px)",
data=image_data,
file_name=f"{file_prefix}.{export_format.lower()}",
mime=mime_types[export_format],
use_container_width=True
)
# Display QR code info
with st.expander("QR Code Information"):
st.write(f"**Type:** {qr_mode}")
if qr_mode == "URL":
st.write(f"**URL:** {qr_content}")
else:
st.write(f"**Network:** {wifi_ssid}")
st.write(f"**Security:** {wifi_security}")
st.write(f"**Hidden:** {'Yes' if wifi_hidden else 'No'}")
st.write(f"**Error Correction:** {error_correction}")
st.write(f"**Format:** {export_format}")
if export_format in ["PNG", "JPEG"]:
st.write(f"**Resolution:** {target_size}x{target_size}px")
st.write(f"**Logo:** {'Yes' if logo_file else 'No'}")
except Exception as e:
st.error(f"Error generating QR code: {str(e)}")
st.exception(e)
# Footer
st.divider()
st.markdown(
"""
<div style='text-align: center; color: gray; font-size: 0.9em;'>
<p>Built with Streamlit | QR Code Generator v1.0</p>
<p>Tip: Use high error correction (H) when adding logos</p>
</div>
""",
unsafe_allow_html=True
)
if __name__ == "__main__":
main()