codelion's picture
Update app.py
2c7c7db verified
import gradio as gr
import PIL
from PIL import Image
import os
import tempfile
import zipfile
import shutil
from pathlib import Path
import numpy as np
# Define target sizes for different viewports
SIZES = [
(480, 423),
(696, 613),
(960, 846),
(1095, 965),
(1280, 1128),
(1440, 1269),
(1670, 1472),
(1870, 1648),
(2048, 1805)
]
def resize_image(img, target_size):
"""Resize image maintaining aspect ratio"""
img_copy = img.copy()
return img_copy.resize(target_size, PIL.Image.Resampling.LANCZOS)
def generate_html_snippet(image_path_prefix):
"""Generate HTML code snippet with srcset"""
srcset_items = [f"{image_path_prefix}-{w}x{h}.jpg {w}w" for w, h in SIZES]
srcset_str = ",\n ".join(srcset_items)
sizes_items = [
f"(max-width: {w}px) {w}px" for w, _ in SIZES[:-1]
] + [f"{SIZES[-1][0]}px"]
sizes_str = ",\n ".join(sizes_items)
# Using min-width for better responsive behavior
# sizes_str = "(min-width: 1000px) 45vw, (min-width: 780px) 696px, (min-width: 580px) 480px, calc(100vw - 60px)"
# Use the middle size as default src
default_size = SIZES[4] # 1280x1128
html = f'''<!-- Responsive Image -->
<img
src="{image_path_prefix}-{default_size[0]}x{default_size[1]}.jpg"
srcset="
{srcset_str}
"
sizes="
{sizes_str}
"
alt="Your image description"
style="max-width: 100%; height: auto;"
>'''
return html
def get_path_components(filepath):
"""Split filepath into directory and filename"""
dirpath = os.path.dirname(filepath)
filename = os.path.basename(filepath)
base_filename = os.path.splitext(filename)[0]
return dirpath, base_filename
def process_image(input_img, input_path):
"""Main processing function"""
if input_img is None:
return None, None, "Please upload an image"
# Create temporary directory for processed images
temp_dir = tempfile.mkdtemp()
zip_path = os.path.join(temp_dir, "responsive_images.zip")
processed_paths = [] # Initialize the list outside try block
try:
# Get path components
if input_path and input_path.strip():
dirpath, base_filename = get_path_components(input_path.strip())
else:
# If no path provided, use default
dirpath, base_filename = "", "image"
# Convert to PIL Image if needed
if isinstance(input_img, np.ndarray):
img = Image.fromarray(input_img)
else:
img = input_img
# Convert to RGB if necessary
if img.mode != 'RGB':
img = img.convert('RGB')
# Process each size
for width, height in SIZES:
# For zip file, only use filename without path
output_path = os.path.join(temp_dir, f"{base_filename}-{width}x{height}.jpg")
resized = resize_image(img, (width, height))
resized.save(output_path, "JPEG", quality=90)
processed_paths.append(output_path)
# Create zip file
with zipfile.ZipFile(zip_path, 'w') as zf:
for path in processed_paths:
zf.write(path, os.path.basename(path))
# Generate HTML snippet using full path
full_path = dirpath + ("/" if dirpath else "") + base_filename
html_snippet = generate_html_snippet(full_path)
return zip_path, html_snippet, "Processing completed successfully!"
except Exception as e:
if os.path.exists(zip_path):
try:
os.remove(zip_path)
except:
pass
return None, None, f"Error processing image: {str(e)}"
finally:
# Clean up temporary files except zip
for path in processed_paths:
try:
os.remove(path)
except:
pass
# Try to remove the temp directory if it's empty
try:
os.rmdir(temp_dir)
except:
pass
# Create Gradio interface
with gr.Blocks(title="Responsive Image Generator") as app:
gr.Markdown("""
# Responsive Image Generator
Upload an image to generate optimized versions for different viewport sizes.
You'll receive:
1. A ZIP file containing all sized versions
2. HTML code snippet with proper srcset attributes
Optional: Specify the full path where images will be stored (e.g., 'assets/images/about/mock-up.png')
""")
with gr.Row():
with gr.Column():
with gr.Row():
input_image = gr.Image(
label="Upload Original Image",
type="pil",
show_label=True
)
with gr.Row():
input_path = gr.Textbox(
label="Image Path (optional)",
placeholder="e.g., assets/images/about/mock-up.png",
value=""
)
process_btn = gr.Button("Process Image")
with gr.Column():
output_zip = gr.File(label="Download Processed Images")
output_html = gr.Code(
label="HTML Code Snippet",
language="html"
)
output_message = gr.Textbox(label="Status")
def handle_upload(img):
"""Handle image upload to get filename"""
if isinstance(img, dict) and 'name' in img:
return img['name']
return ""
# Update filename when image is uploaded
input_image.upload(
fn=handle_upload,
inputs=[input_image],
outputs=[input_path]
)
# Process button click
process_btn.click(
fn=process_image,
inputs=[input_image, input_path],
outputs=[output_zip, output_html, output_message]
)
# Launch the app with share=True for public access
app.launch(share=True)