- Add _vulkan_available(): checks /dev/dri/renderD* on Linux, assumes
true on macOS/Windows; set REALESRGAN_NCNN=force to override
- Add _test_ncnn_binary(): test-runs the binary after install and checks
stderr for "no vulkan" — marks skipped if Vulkan init fails at runtime
- ensure_ncnn_installed() now returns early with state=skipped when no
Vulkan detected, avoiding a wasted ~30MB download on CPU-only servers
- Recommend PyTorch CPU when available on headless (AI quality, slow but
works); Lanczos as final fallback
- Frontend: handle state=skipped immediately (no polling needed), show
brief informational toast; show "Headless server" note in dialog
https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
- upscale.py: add InstallStatus dataclass + ensure_ncnn_installed() async
function that downloads and extracts the NCNN binary for the current
platform (Linux/macOS/Windows), tracks progress (0-100%), and busts the
caps cache when done
- main.py: trigger ensure_ncnn_installed() as a background task on app
startup when no AI upscaler is detected
- print_tools.py: /upscale/available triggers install task when no AI
upscaler found; new GET /upscale/install-status endpoint for polling
- upscale.js: if no AI upscaler on open, poll install-status showing a
progress bar notification, then refresh caps and proceed when done
https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
Detection priority (probed once, cached):
1. Real-ESRGAN PyTorch + CUDA GPU → fastest, best quality
2. Real-ESRGAN PyTorch + Apple MPS → fast on Apple Silicon
3. Real-ESRGAN NCNN Vulkan binary → fast on any GPU via Vulkan (no CUDA needed)
4. Real-ESRGAN PyTorch CPU → works, slow (warned in UI)
5. Lanczos → always available, instant fallback
Backend:
- services/upscale.py: full capability probe (probe_upscale_capabilities),
implementations for PyTorch (CUDA/MPS/CPU auto-device) and NCNN binary,
upscale_sync() resolves method with fallback chain,
async upscale_image() runs in thread pool
- print_tools.py: /api/print/upscale uses new service; method="auto" by default;
GET /api/print/upscale/available returns full capability map with device info
and recommended_label; POST /api/print/upscale/refresh-caps busts cache
without restart (useful after installing NCNN binary into container)
Frontend:
- upscale.js: fetches capability map on first open; builds method selector showing
only available options; labels recommended method with ★; shows device info
(CUDA/MPS/CPU/NCNN) in dialog; maps display label back to method key on submit;
shows actual method used in success toast and undo history entry
Scripts:
- scripts/download_realesrgan.py: downloads NCNN Vulkan binary for current platform
(Linux/macOS/Windows) to /app/data/models/realesrgan/; makes executable;
run inside container or locally
https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
Backend — new /api/print/* router:
- POST /api/print/frame-fit: fit image to 4x6/5x7/8x10/11x14/16x20/20x24/24x36
and square sizes (4x4/8x8/12x12) at configurable DPI.
Three modes:
crop — center-crop to aspect ratio, Lanczos scale to print res (no AI)
extend — scale to fill one dimension, AI-inpaint the gap; mirror-fill fallback
smart — auto: extend if gap < 15% of frame dimension, else crop
Auto-detects orientation from image shape; respects explicit portrait/landscape.
- POST /api/print/upscale: Lanczos scale (always) or Real-ESRGAN (if installed)
- GET /api/print/frame-sizes: frame catalogue with pixel dimensions at 300dpi
- GET /api/print/upscale/available: reports whether Real-ESRGAN is installed
Frontend:
- modules/image/frame_fit.js: dialog with frame size, orientation, mode, DPI,
optional extend prompt; shows current image size; result as new layer option
- modules/image/upscale.js: dialog with scale factor (1.5–4×), method selector
(auto-hides AI option if Real-ESRGAN not available); result as new layer option
- config-menu.js: Fit to Frame... and Upscale... added under Image menu
https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
Each operation (inpaint, txt2img, img2img, outpaint) can now use a different
provider. Resolution order: per-op override → global AI_PROVIDER default.
Example: txt2img→openai, inpaint→invokeai, everything else→invokeai default.
Backend:
- config.py: add AI_PROVIDER_INPAINT / TXT2IMG / IMG2IMG / OUTPAINT settings
- remote_provider.py: get_remote_provider(operation) resolves override then default;
_build_provider() extracted as shared factory; _OP_FIELD maps op→setting name
- ai_tools.py: each endpoint passes its operation to _require_remote();
GET /api/config runs per-op health checks concurrently, returns operations map
and overrides; POST /api/config accepts and applies per-op override fields
Frontend:
- ai_provider_settings.js: four new selects (inpaint/txt2img/img2img/outpaint);
persists to localStorage and sends per-op fields to POST /api/config
- provider-badge.js: shows override summary (e.g. "invokeai · txt2img→openai")
and per-op health in tooltip
- .env.example: document per-op override env vars with examples
https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
Frontend:
- tools/ai_replace_selection.js: use any selection → remote inpaint with prompt
- modules/generate/text_to_image.js: Text → Image dialog (new layer or replace canvas)
- modules/generate/outpaint.js: Expand Canvas in any direction via remote provider
- modules/tools/ai_provider_settings.js: in-app provider config (OpenAI / InvokeAI /
ComfyUI / Replicate); persists to localStorage, pushes to POST /api/config at runtime
- config.js: register ai_replace_selection tool
- config-menu.js: add Generate menu (Text→Image, Outpaint); AI Provider Settings under Tools
- modules/help/about.js: updated credits (LaMa, rembg, SAM, InvokeAI, ComfyUI, OpenAI)
- api/capabilities.js: add refreshCapabilities() for post-save cache invalidation
Backend:
- routers/ai_tools.py: POST /api/config — apply provider settings at runtime
without restart (session-scoped, non-persistent; .env for permanence)
https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
- Switch U2Net from onnxruntime to OpenCV DNN to avoid
"cannot enable executable stack" error in Docker
- Add alertify dialog styling to fix white text on white
background issue in popups
- Add offerFloatSelection() to AI Paint that prompts user
after selection to move/scale it (Canva-like workflow)
- Auto-switch to Select tool after floating selection
https://claude.ai/code/session_01CLedz6CanT9t46KBvng3vz
- Fix brush_select isProcessing flag not resetting after first use
(reset in on_leave() when switching tools)
- Add onnxruntime dependency for U2net background removal
- Use full U2net model (176MB) instead of lightweight for better quality
https://claude.ai/code/session_01CLedz6CanT9t46KBvng3vz
- Fix brush_select and smart_select mask scaling to match layer dimensions
- Add "Float Selection" feature to Select tool - when switching to Select
with an active AI selection, offers to copy it to a movable layer
- Add aspect ratio lock toggle (🔗 button) in layer details panel
- When locked, changing width auto-updates height and vice versa
- Add U2net model auto-download - will download lightweight u2netp.onnx (~4MB)
automatically if no model found
- Improve error messages for background removal
- Register on_activate for select tool in config
Workflow: Select object with AI tool → Click Select tool → "Float" selection
→ Move/scale the floated layer freely
https://claude.ai/code/session_01CLedz6CanT9t46KBvng3vz
- Fix My Library: Add CSS styling for library browser, items now visible
- Integrate My Library into Shapes tool with tabbed interface
- Improve AI Inpaint: Add transform mode for scaling/sizing selections
- Add helpful guidance explaining inpaint vs transform modes
- Add U2net as alternative background removal (avoids rembg issues)
- Create U2net model definition and download script
- Improve Caddyfile with multiple options and troubleshooting guide
Note: Brush Select (AI Paint) tool was already implemented and working.
https://claude.ai/code/session_01CLedz6CanT9t46KBvng3vz
- Save layer or selection to personal library
- Browse library with category grouping and thumbnails
- Insert assets as new layers (double-click or Insert button)
- Delete unwanted assets
- Export library to JSON for backup
- Import library from JSON backup
- Assets stored in browser IndexedDB (persistent)
- Categories: General, Shapes, Borders, Icons, Templates, etc.
- New Image > Selection Effects submenu
- Invert Selection: Invert colors only within selected area
- Adjust Selection: Brightness/contrast/gamma on selection only
- Greyscale Selection: Convert just the selected area to greyscale
- All effects work with any selection tool (Smart Select, Brush Select, etc.)
- Useful for CNC depth maps where specific objects need different treatments
- New tool: Paint/brush over objects to select them
- AI (SAM) detects actual object boundaries from brush strokes
- Collects sample points along brush path, sends to SAM
- Combines multiple masks for multi-object selection
- Shift+brush to add to existing selection
- Full cut/copy/delete support with mask-shaped results
- Visual feedback: brush stroke preview, sample points, marching ants
- Fix cut/copy to preserve mask shape with transparency
- Add missing CSS icons for magic_wand, lasso, ellipse_select tools
- Fix toast messages styling (visible on dark theme)
- Update AI Inpaint to work with all selection tools
- Change tab title to +miniPaint
- Add DNS config to docker-compose for external API access
Frontend:
- Added "Remove Background (AI)" to Image menu
- Created remove_background.js module with dialog options
- Added removeBackground method to API service
Backend:
- Added /tools/remove-background-base64 endpoint for miniPaint frontend
- Uses rembg library for AI-powered background removal
Features:
- Automatically detects main subject and removes background
- Option to create as new layer or replace current
- Enables transparency mode after removal
- Works with any image layer
New Selection Tools:
- Magic Wand: Click to select by color similarity (like GIMP)
- Configurable tolerance (0-100%)
- Contiguous or global mode
- Shift+Click to add to selection
- Lasso: Freehand selection by drawing
- Draw around area to select
- Shift+Draw to add to selection
- Ellipse Select: Draw elliptical/circular selections
- Drag to create ellipse
- Shift+Drag for perfect circle
- Alt+Drag to draw from center
Smart Select Improvements:
- Fixed copy/cut to layer errors
- Added Shift+Click for multi-select (additive selection)
- All operations use proper layer action system
All selection tools support:
- Ctrl+C: Copy selection to new layer
- Ctrl+X: Cut selection to new layer
- Delete: Delete selected area
- Escape: Clear selection
- Marching ants animation on selection edge
- SAM selection now shows actual mask contour instead of bounding box
- Added marching ants animation on the actual mask edge
- Added keyboard shortcuts:
- Ctrl+C: Copy selection to new layer
- Ctrl+X: Cut selection to new layer (removes from original)
- Delete: Delete selected area
- Escape: Clear selection
- Removed eye catalog download from startup (was failing with 429)
Frontend:
- Fix smart_select.js to properly render mask overlay
- Add marching ants border around selection
- Calculate selection bounds from mask
- Trigger re-render after mask is loaded
Backend:
- Fix inpaint endpoint to call edit_image() instead of inpaint()
- The AI providers use edit_image() method, not inpaint()
New features:
- Smart Select tool: Click to select objects using SAM (Segment Anything)
- AI Inpaint tool: Edit selected regions with text prompts
Changes:
- frontend/src/js/tools/smart_select.js: SAM-powered selection tool
- frontend/src/js/tools/ai_inpaint.js: AI inpainting with prompt dialog
- frontend/src/js/services/api.js: API service for backend communication
- frontend/src/js/config.js: Register new tools
- frontend/src/css/layout.css: Tool icon styles
- frontend/images/icons/: SVG icons for new tools
- backend/app/routers/tools.py: New base64 API endpoints
- frontend/Dockerfile: Updated for miniPaint build
- frontend/nginx.conf: Added /api prefix proxy
ROOT CAUSE: ImageCanvas referenced props that don't exist:
- activeTool, onSmartSelect, onColorSelect were used but never declared
- selectionMode checked for 'smart'/'color' but App passes advancedToolMode with 'smart-select'/'color-select'
Changes:
- Update mode checking to use advancedToolMode instead of selectionMode for smart/color select
- Replace onSmartSelect/onColorSelect calls with onAdvancedToolClick
- Fix useEffect dependency array to reference actual props
- Add missing state/refs: currentZoom, imageRef, baseScaleRef, isDrawingRef
- Add zoom control buttons to canvas UI
- Fix tool mode indicator to check advancedToolMode
- Add zoom support via prop (scales image around center)
- Fix selection interaction: clicking on selection transforms, clicking elsewhere creates new
- Use refs for state accessed in event handlers (fixes stale closure issue)
- Add smart select mode (clicks call onSmartSelect with image coordinates)
- Add color select mode placeholder
- Add pan mode with cursor feedback
- Add move mode for manipulating selections
- Use dashed blue selection style (more visible)
- forwardRef to expose canvas methods
- Redesign layout: left toolbar, center canvas, right sidebar
- Add vertical tool strip with keyboard shortcuts (V, R, E, F, W, B, G, Z, H)
- Collapsible sidebar panels: Tool Options, AI Edit, Quick Actions, Eyes, Layers, History
- Canvas now fills available space with checkerboard background
- Add zoom controls in status bar
- Add menu bar with New, Save, Reset
- Remove old multi-column layout
Frontend changes:
- Wire Smart Select and Color Select to canvas click handlers
- Add externalSelection prop to ImageCanvas for displaying AI-generated selections
- Add zoom controls (mouse wheel + buttons) to ImageCanvas
- Fix layer buttons (New Layer, Delete, Duplicate) with proper handlers
- Lift advancedToolMode state to App.jsx for coordination between components
- Add tool mode indicator overlay on canvas
Backend changes:
- Update smart-select endpoint to return JSON with polygon and bbox data
- Update color-select endpoint to return JSON with polygon and bbox data
- Add _mask_to_polygon helper function using OpenCV contour detection
- Add cv2 and base64 imports to tools.py
API changes:
- smartSelect and colorSelect now return { polygon, bbox, mask_base64 }
Backend:
- Add /tools router with background removal, smart select, color select
- Add rembg dependency for AI background removal
- Add layer management API (list, flatten)
- Fix transparency preservation in blend_patch (veil collapse fix)
- Preserve alpha channel when reverting/resetting images
Frontend:
- Add AdvancedTools panel with background removal, smart select, color select
- Add Layers panel with drag-to-reorder, visibility toggle, flatten
- Add toolsApi for new backend endpoints
- Make right panel scrollable for additional controls
This adds "Photoshop light" capabilities:
- Remove background and create layer
- Smart object selection (click to select)
- Color selection with tolerance
- Layer system with compositing
Fixes:
- Remove scale limit to allow image to fill canvas
- Fix Lasso tool by using Polygon instead of Polyline
- Remove duplicate Clear Selection button
- Fix Undo/Redo dependencies with useCallback
New Features:
- Eye Catalog UI for browsing and applying saved eyes
- Upload new eyes to catalog
- Apply eyes to selected areas with feathering
- Delete eyes from catalog
- Make canvas use full viewport height for larger image display
- Add download button to export edited images
- Implement Undo/Redo with Ctrl+Z / Ctrl+Y keyboard shortcuts
- Add transform controls for selections (move, resize, rotate)
- Add warn on reload to prevent data loss
- Make project naming optional, auto-generate from filename
- Fixed nginx.conf to proxy all API routes (/patches, /generate, /health, /docs)
- Changed frontend port to 3080 in docker-compose.yml
- Added Caddyfile for Caddy2 reverse proxy configuration
- Supports both FQDN and IP:port configurations
This commit implements a full-stack AI photo editing application that
allows users to regenerate only selected areas of images using AI.
Features implemented:
- Frontend (React + Fabric.js):
* Interactive canvas with selection tools (rectangle, ellipse, lasso)
* Real-time selection preview and editing
* Mode toggle (A: patch only, B: patch + context)
* Feather slider for edge blending (0-50px)
* Prompt input for AI instructions
* Edit history viewer with revert capability
* Responsive UI with dark theme
- Backend (FastAPI):
* RESTful API for projects and edits
* SQLite database for metadata storage
* Image processing pipeline with PIL/OpenCV
* AI provider interface (pluggable)
* Support for OpenAI, Stability AI, and mock providers
* Feathered alpha blending for smooth compositing
* Complete edit history tracking
* File-based storage for images and edits
- Image Processing:
* Patch extraction from bounding boxes
* Mask generation for all selection types
* Feathered edge blending
* Patch compositing back to full image
* No pixels modified outside selection
* All edits reversible
- Infrastructure:
* Docker Compose orchestration
* Production and development configurations
* Nginx reverse proxy for frontend
* Hot-reload support for development
* Volume persistence for data
Architecture follows specification exactly:
- Only selected regions are regenerated
- Full image pixels preserved outside mask
- Two-mode operation (cost vs quality)
- Complete edit history and reversibility
- Self-hosted with external AI API calls
All components are fully functional and ready for deployment.