import gradio as gr import cv2 import numpy as np from registry import registry from filters import * from components import create_filter_controls def create_app(): with gr.Blocks(theme=gr.themes.Soft(), css=""" .gradio-container { max-width: 1600px !important; margin: auto !important; } .filter-header { text-align: center; padding: 30px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 15px; margin-bottom: 30px; box-shadow: 0 10px 30px rgba(0,0,0,0.2); } .filter-header h1 { color: white !important; margin: 0; font-size: 2.5em; font-weight: bold; } .filter-header p { color: rgba(255,255,255,0.95) !important; margin: 10px 0 0 0; font-size: 1.1em; } .filter-header a { color: rgba(255,255,255,0.9) !important; text-decoration: none; font-weight: 500; transition: all 0.3s ease; } .filter-header a:hover { color: white !important; text-decoration: underline; } .image-container { border-radius: 12px; padding: 15px; transition: all 0.3s ease; } .image-container:hover { transform: translateY(-2px); } .control-panel { border-radius: 12px; padding: 20px; margin-top: 15px; } .filter-description { padding: 15px; border-radius: 8px; margin: 15px 0; border-left: 4px solid #667eea; } .gr-button-primary { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; border: none !important; font-weight: bold !important; color: white !important; transition: all 0.3s ease !important; } .gr-button-primary:hover { transform: translateY(-2px) !important; box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4) !important; } .gr-button-secondary { transition: all 0.3s ease !important; } .gr-button-secondary:hover { transform: translateY(-2px) !important; } .stats-panel { border-radius: 8px; padding: 15px; margin-top: 10px; text-align: center; } /* Dark mode compatibility */ .dark .filter-description { background: rgba(255,255,255,0.05); } .dark .image-container { background: rgba(255,255,255,0.02); } .dark .control-panel { background: rgba(255,255,255,0.03); } /* Light mode */ .filter-description { background: #f0f4f8; } .image-container { background: rgba(0,0,0,0.02); } .control-panel { background: linear-gradient(to bottom, #f8f9fa, #ffffff); } """) as app: # Header with gr.Column(elem_classes="filter-header"): gr.Markdown(""" # 📷 Photo Filter App Professional photo editing with powerful filters - Fast & Easy Built with [anycoder](https://huggingface.co/spaces/akhaliq/anycoder) """) # Initialize components filter_names = list(registry.filters.keys()) # Top Row - Images side by side with gr.Row(): # Left Column - Input Image with gr.Column(scale=1): with gr.Group(elem_classes="image-container"): input_image = gr.Image( label="📤 Original Image", type="numpy", height=500 ) # Right Column - Output Image with gr.Column(scale=1): with gr.Group(elem_classes="image-container"): output_image = gr.Image( label="✅ Edited Image", height=500 ) error_message = gr.Markdown(visible=False) with gr.Row(): download_button = gr.Button( "💾 Download", visible=False, size="lg" ) # Action Buttons with gr.Row(): apply_button = gr.Button( "✨ Apply Filter", variant="primary", size="lg", scale=2 ) reset_button = gr.Button( "🔄 Reset", variant="secondary", size="lg", scale=1 ) # Bottom Row - Filter Selection & Parameters with gr.Row(): with gr.Column(scale=1): with gr.Group(elem_classes="control-panel"): gr.Markdown("### 🎨 Select Filter") filter_select = gr.Dropdown( label="Filter", choices=filter_names, value="Original", interactive=True ) filter_doc = gr.Markdown( value="Select a filter to see detailed description.", elem_classes="filter-description" ) with gr.Column(scale=1): with gr.Group(elem_classes="control-panel"): gr.Markdown("### ⚙️ Customize") # Create dynamic filter controls filter_controls, control_components = create_filter_controls() # Stats panel with gr.Row(): with gr.Column(): gr.Markdown( f"""
📊 Total Filters: {len(filter_names)} | 🎯 Parameterized Filters: {sum(1 for f in filter_names if registry.params_map.get(f))} | 🚀 Quick Filters: {sum(1 for f in filter_names if not registry.params_map.get(f))}
""" ) # Handle UI updates def update_controls(filter_name): updates = [] for group_name in filter_controls: updates.append(gr.update(visible=group_name == filter_name)) doc = registry.filters[filter_name].__doc__ or "No detailed description available." return updates + [doc] # Handle image processing def process(image, filter_name, *args): if image is None: return None, gr.update(visible=True, value="⚠️ **Note:** Please upload an image before applying filters!"), gr.update(visible=False) try: image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) # Get parameters for current filter params = {} if filter_name in control_components: param_names = list(registry.params_map.get(filter_name, {}).keys()) controls_list = control_components[filter_name] for i, param_name in enumerate(param_names): if i < len(controls_list): params[param_name] = args[i] processed = registry.filters[filter_name](image, **params) if len(processed.shape) == 2: processed = cv2.cvtColor(processed, cv2.COLOR_GRAY2RGB) else: processed = cv2.cvtColor(processed, cv2.COLOR_BGR2RGB) return processed, gr.update(visible=False), gr.update(visible=True) except Exception as e: return None, gr.update(visible=True, value=f"❌ **Error:** {str(e)}"), gr.update(visible=False) # Handle reset def reset_all(): return None, None, gr.update(visible=False), gr.update(visible=False), "Original" # Collect all control components all_control_components = [] for filter_name in control_components: all_control_components.extend(control_components[filter_name]) # Connect events filter_select.change( update_controls, inputs=filter_select, outputs=list(filter_controls.values()) + [filter_doc], api_name=False ) input_components = [input_image, filter_select] + all_control_components apply_button.click( process, inputs=input_components, outputs=[output_image, error_message, download_button], ) reset_button.click( reset_all, inputs=None, outputs=[input_image, output_image, error_message, download_button, filter_select] ) return app if __name__ == "__main__": app = create_app() app.launch()