initial commit
This commit is contained in:
285
app.py
Normal file
285
app.py
Normal file
@@ -0,0 +1,285 @@
|
||||
"""
|
||||
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()
|
||||
Reference in New Issue
Block a user