| import gradio as gr |
| import os |
| from pathlib import Path |
| from PIL import Image |
| import json |
| from datetime import datetime |
|
|
| |
| UPLOAD_DIR = "images/uploads" |
| GALLERY_DIR = "images/gallery" |
| METADATA_FILE = "images/metadata.json" |
|
|
| |
| os.makedirs(UPLOAD_DIR, exist_ok=True) |
| os.makedirs(GALLERY_DIR, exist_ok=True) |
|
|
| def load_metadata(): |
| """Load metadata from JSON file""" |
| if os.path.exists(METADATA_FILE): |
| with open(METADATA_FILE, 'r') as f: |
| return json.load(f) |
| return {} |
|
|
| def save_metadata(metadata): |
| """Save metadata to JSON file""" |
| with open(METADATA_FILE, 'w') as f: |
| json.dump(metadata, f, indent=2) |
|
|
| def get_gallery_images(): |
| """Get all images from gallery directory""" |
| images = [] |
| if not os.path.exists(GALLERY_DIR): |
| return images |
| |
| for file in sorted(os.listdir(GALLERY_DIR)): |
| if file.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.webp')): |
| filepath = os.path.join(GALLERY_DIR, file) |
| images.append(filepath) |
| return images |
|
|
| def upload_image(file): |
| """Handle image upload""" |
| if file is None: |
| return "No file uploaded", get_gallery_images() |
| |
| try: |
| |
| if hasattr(file, 'name'): |
| filename = os.path.basename(file.name) |
| file_path = file.name |
| else: |
| filename = os.path.basename(str(file)) |
| file_path = str(file) |
| |
| save_path = os.path.join(GALLERY_DIR, filename) |
| |
| |
| img = Image.open(file_path) |
| img.save(save_path) |
| |
| |
| metadata = load_metadata() |
| metadata[filename] = { |
| "uploaded": datetime.now().isoformat(), |
| "size": f"{img.width}x{img.height}", |
| "format": img.format |
| } |
| save_metadata(metadata) |
| |
| return f"β
Image '{filename}' uploaded successfully!", get_gallery_images() |
| except Exception as e: |
| return f"β Error uploading image: {str(e)}", get_gallery_images() |
|
|
| def delete_image(gallery_state): |
| """Delete image from gallery - requires Gradio 6.20+ select callback""" |
| if not gallery_state: |
| return "No image selected", get_gallery_images() |
| |
| try: |
| |
| image_path = gallery_state |
| if isinstance(gallery_state, dict): |
| image_path = gallery_state.get('name') or gallery_state.get('image') |
| |
| if image_path and os.path.exists(image_path): |
| os.remove(image_path) |
| |
| |
| filename = os.path.basename(image_path) |
| metadata = load_metadata() |
| if filename in metadata: |
| del metadata[filename] |
| save_metadata(metadata) |
| |
| return f"β
Image deleted!", get_gallery_images() |
| else: |
| return "β Image not found", get_gallery_images() |
| except Exception as e: |
| return f"β Error: {str(e)}", get_gallery_images() |
|
|
| def search_images(query): |
| """Search images by filename""" |
| all_images = get_gallery_images() |
| if not query: |
| return all_images |
| |
| query = query.lower() |
| return [img for img in all_images if query in os.path.basename(img).lower()] |
|
|
| |
| with gr.Blocks(title="Image Gallery", theme=gr.themes.Soft()) as demo: |
| gr.Markdown("# πΌοΈ Image Gallery") |
| gr.Markdown("A simple image gallery built with Gradio. Upload, organize, and view your images.") |
| |
| with gr.Tabs(): |
| |
| with gr.Tab("πΈ Gallery"): |
| gallery_output = gr.Gallery( |
| label="Images", |
| value=get_gallery_images(), |
| columns=4, |
| rows=3, |
| object_fit="scale-down", |
| height="auto" |
| ) |
| |
| with gr.Row(): |
| search_input = gr.Textbox( |
| label="Search", |
| placeholder="Search images by filename..." |
| ) |
| search_btn = gr.Button("π Search") |
| |
| with gr.Row(): |
| refresh_btn = gr.Button("π Refresh Gallery") |
| |
| search_btn.click( |
| search_images, |
| inputs=search_input, |
| outputs=gallery_output |
| ) |
| |
| refresh_btn.click( |
| lambda: get_gallery_images(), |
| outputs=gallery_output |
| ) |
| |
| |
| with gr.Tab("β¬οΈ Upload"): |
| gr.Markdown("### Upload New Images") |
| |
| with gr.Row(): |
| file_input = gr.File( |
| label="Select Image", |
| file_count="single", |
| file_types=["image"] |
| ) |
| upload_btn = gr.Button("Upload") |
| |
| upload_status = gr.Textbox(label="Status", interactive=False) |
| |
| uploaded_gallery = gr.Gallery( |
| label="Recent Uploads", |
| columns=4, |
| rows=2, |
| object_fit="scale-down" |
| ) |
| |
| upload_btn.click( |
| upload_image, |
| inputs=file_input, |
| outputs=[upload_status, uploaded_gallery] |
| ) |
| |
| |
| with gr.Tab("βοΈ Manage"): |
| gr.Markdown("### Manage Images") |
| |
| manage_gallery = gr.Gallery( |
| value=get_gallery_images(), |
| label="Gallery Images", |
| columns=4, |
| rows=3, |
| object_fit="scale-down", |
| interactive=True, |
| show_label=True |
| ) |
| |
| with gr.Row(): |
| refresh_manage_btn = gr.Button("π Refresh") |
| |
| action_status = gr.Textbox(label="Status", interactive=False) |
| |
| refresh_manage_btn.click( |
| lambda: get_gallery_images(), |
| outputs=manage_gallery |
| ) |
| |
| |
| with gr.Tab("βΉοΈ Info"): |
| gr.Markdown(""" |
| ## About This Gallery |
| |
| **Features:** |
| - π€ Upload images (PNG, JPG, GIF, WebP) |
| - π Search and filter by filename |
| - ποΈ Organize and manage images |
| - π View image metadata (size, format) |
| - π³ Run anywhere with Docker |
| |
| **Supported Formats:** |
| - PNG |
| - JPEG/JPG |
| - GIF |
| - WebP |
| |
| **Storage:** |
| - Gallery: `images/gallery/` |
| - Metadata: `images/metadata.json` |
| |
| **Version Info:** |
| - Python: 3.13+ |
| - Gradio: 6.20.0+ |
| - Pillow: 10.2.0+ |
| """) |
|
|
| if __name__ == "__main__": |
| demo.launch( |
| server_name="0.0.0.0", |
| server_port=7860, |
| share=False |
| ) |
|
|