import streamlit as st def render_sidebar(reset_generation_state): st.sidebar.title("Navigation") app_page = st.sidebar.radio( "Go to Page:", [ "🎨 Image-to-SVG Vectorizer", "🛠️ Tool Extract", "⚡ Interactive Node Simplifier" ] ) # Only show controls on vectorizer page if app_page == "🎨 Image-to-SVG Vectorizer": st.sidebar.header("⚙️ Adjustment Controls") # ---------------------------------------------------------------- # 1. DEFINE PRESET TEMPLATES & OPTIONS # ---------------------------------------------------------------- # Add "Custom" to the options list quality_options = [ "High (Detailed)", "Moderate (Balanced)", "Low (Blurry/Sketchy)", "Custom" ] # Preset values maps presets = { "High (Detailed)": {"scale_val": 2.5, "canny_low_val": 5, "canny_high_val": 40}, "Moderate (Balanced)": {"scale_val": 2.0, "canny_low_val": 10, "canny_high_val": 70}, "Low (Blurry/Sketchy)": {"scale_val": 1.2, "canny_low_val": 40, "canny_high_val": 150} } # Initialize session state variables safely on first run if "quality_val" not in st.session_state: st.session_state.quality_val = "Moderate (Balanced)" if "scale_val" not in st.session_state: st.session_state.scale_val = 2.0 if "canny_low_val" not in st.session_state: st.session_state.canny_low_val = 10 if "canny_high_val" not in st.session_state: st.session_state.canny_high_val = 70 # ---------------------------------------------------------------- # 2. CALLBAK FUNCTIONS FOR STATE MANAGEMENT # ---------------------------------------------------------------- def on_preset_change(): """Triggered when the user changes the dropdown explicitly.""" reset_generation_state() selected = st.session_state.quality_val # If they chose a real template, force-apply those values if selected in presets: st.session_state.scale_val = presets[selected]["scale_val"] st.session_state.canny_low_val = presets[selected]["canny_low_val"] st.session_state.canny_high_val = presets[selected]["canny_high_val"] def on_slider_change(): """Triggered when user tweaks any preset-controlled slider.""" reset_generation_state() # If they move a slider, flip the dropdown automatically to 'Custom' st.session_state.quality_val = "Custom" # ---------------------------------------------------------------- # 3. QUALITY PRESET DROPDOWN # ---------------------------------------------------------------- current_quality = st.session_state.quality_val idx = quality_options.index(current_quality) if current_quality in quality_options else 1 st.sidebar.selectbox( "Extraction Quality Preset", quality_options, index=idx, key="quality_val", on_change=on_preset_change ) # ---------------------------------------------------------------- # 4. IMAGE CLEAN-UP # ---------------------------------------------------------------- st.sidebar.subheader("Image Clean-up") st.sidebar.slider( "De-blur (Sharpening)", 0.0, 3.0, key="sharpen_val", step=0.1, on_change=reset_generation_state # Independent slider ) st.sidebar.slider( "Resize Scale", 1.0, 3.0, key="scale_val", step=0.1, on_change=on_slider_change # Auto-switches preset to Custom ) # ---------------------------------------------------------------- # 5. BACKGROUND REMOVAL (GRABCUT) # ---------------------------------------------------------------- st.sidebar.subheader("✂️ Background Removal") enable_grabcut = st.sidebar.checkbox( "Isolate Foreground Object", key="enable_grabcut", help="Uses the GrabCut algorithm to eliminate background noise before vectorization.", on_change=reset_generation_state ) if enable_grabcut: st.sidebar.slider( "Background Crop Margin", 1, 50, key="bbox_padding", step=1, help="Tells the algorithm how close the object is to the image edges (in pixels).", on_change=reset_generation_state ) else: st.session_state.bbox_padding = 10 # ---------------------------------------------------------------- # 6. EDGE SETTINGS (CONTAINS PRESET TARGET SLIDERS) # ---------------------------------------------------------------- st.sidebar.subheader("📐 Thresholding & Outlines") st.sidebar.slider( "Canny Low Threshold", 5, 100, key="canny_low_val", on_change=on_slider_change # Auto-switches preset to Custom ) st.sidebar.slider( "Canny High Threshold", 30, 250, key="canny_high_val", on_change=on_slider_change # Auto-switches preset to Custom ) # ---------------------------------------------------------------- # 7. LINE STYLE # ---------------------------------------------------------------- st.sidebar.subheader("🖋️ Line Styling") skeletonize = st.sidebar.checkbox( "Skeletonize (Single-Pixel Path)", key="skeletonize_val", on_change=reset_generation_state ) if not skeletonize: st.sidebar.slider( "Contour Thickness", 1, 5, key="contour_thickness_val", on_change=reset_generation_state ) st.sidebar.slider( "Line Thicken (Dilate)", 0, 3, key="dilate_iter_val", on_change=reset_generation_state ) else: st.session_state.contour_thickness_val = 1 st.session_state.dilate_iter_val = 0 return app_page