CRITICAL fixes:
- #14: Render source image on canvas via Konva Image + use-image hook
- #3: Wire move tool handlers (onClick, onDragEnd, onTransformEnd, draggable)
to all CanvasObjectRenderer shapes
- #4: Implement image object rendering for fill/gradient output
- #2: Show fallback text in histogram panel when no imageData provided
- #1: Forward all args in zundo handleSet debounce wrapper
HIGH fixes:
- #5: Track raw screen cursor position for brush overlay instead of
using canvas-space coordinates
- #6: Export dialog uses Konva stage.toDataURL via module-level ref
instead of DOM querySelector for correct export at any zoom/pan
- #7: Add _historyVersion increment to setAdjustment, resetAdjustments,
toggleFilter, and setFilterParam for undo tracking
- #8: Include lastAction in partialize so history labels display correctly
MEDIUM fixes:
- #10: Move useEditorShortcuts from EditorCanvas to EditorPage with
save/export callbacks
- #11: Remove _historyVersion increment from updateObject to prevent
brush strokes from flooding undo history
- #12: Apply Konva filters (Brighten, Contrast, HSL, Blur, Grayscale,
Sepia, Invert, Pixelate, Emboss, Posterize, Noise, Solarize,
Threshold, Kaleidoscope) to source image node based on store state
- Show desktop-recommended message on mobile viewports (<768px)
- Add LoadingOverlay component for canvas loading/progress states
- Add ARIA tablist/tab/aria-selected to right panel tabs
- Add "Open in Editor" link in review panel after tool processing
Implements Agent 2 deliverables for the image editor: move tool with Konva
Transformer and smart guide snapping, rectangular/elliptical marquee and
lasso selection with marching ants animation, magic wand flood fill, crop
tool with darkened overlay and rule-of-thirds grid, free transform with
numeric inputs, context menu with z-ordering and clipboard operations,
rulers with drag-to-create guides, smart alignment guides, and canvas/image
resize dialogs. Also creates the shared editor types and Zustand store with
full layer management, z-ordering, clipboard, guide, and document operations.
Implement Agent 7 features for the image editor:
- History panel with undo/redo list, action icons, and state jumping
- 51+ keyboard shortcuts via react-hotkeys-hook (tools, modifiers, clipboard)
- Export dialog with PNG/JPEG/WebP format, quality, resize, clipboard copy
- Navigator minimap with viewport rectangle, drag-to-pan, zoom slider
- Autosave/recovery system with localStorage and recovery banner
- Project save/load (.snapotter JSON format)
- Unsaved changes warning via beforeunload
- Paste from system clipboard support
Implements the layer management panel for the image editor (Features 16, 40):
- Blend mode dropdown (16 modes) and opacity slider for active layer
- Layer list with visibility/lock toggles, thumbnails, and inline rename
- Pointer-based drag reorder (not HTML5 drag API)
- Right-click context menu: Duplicate, Merge Down, Flatten All, Delete
- Layer effects section: Drop Shadow, Inner Shadow, Outer Glow, Stroke
- Each effect with enable/disable toggle and full parameter controls
- Wired into EditorRightPanel as the "Layers" tab content
Create the four-zone editor layout shell (toolbar, options bar, status
bar, right panel), welcome screen with drag-and-drop and new document
dialog, and the main editor page with clipboard paste and URL loading.
Add complete type system for the editor (ToolType, CanvasObject, EditorLayer,
EditorState, etc.) and the central Zustand store with zundo undo/redo middleware,
50-entry history limit, 500ms throttle, and O(1) _historyVersion equality checks.
Scans the amd64 Docker image for CRITICAL/HIGH CVEs with available fixes
before publishing multi-arch manifests. Results upload to GitHub Security tab
as SARIF. Blocks release if fixable vulnerabilities are found.
fix: QR code logo causes preview to vanish and become unrecoverable
The QR code generator's logo feature was broken in production (Docker)
due to three interacting issues:
1. The CSP connect-src directive did not include data:, so the
qr-code-styling library's internal XHR to convert logo data URLs to
blobs was silently blocked.
2. crossOrigin: "anonymous" was unnecessarily set on imageOptions for
data URLs.
3. The logo options used a conditional spread that omitted the image key
when no logo was set, but the library's deep merge preserved the
stale data URL.
Closes#121
The QR code generator's logo feature was broken in production (Docker)
due to three interacting issues:
1. The CSP connect-src directive did not include data:, so the
qr-code-styling library's internal XHR to convert logo data URLs to
blobs was silently blocked. The library has no onerror handler, so the
render promise hung forever after the container was already cleared.
2. crossOrigin: "anonymous" was unnecessarily set on imageOptions for
data URLs, which can cause canvas taint issues.
3. The logo options used a conditional spread that omitted the image key
when no logo was set. The library's update() deep-merges options, so
removing the logo preserved the stale data URL and the QR stayed
broken even after logo removal.
Closes#121
Pillow 11.1.0 has CVE-2026-42308, CVE-2026-42310, CVE-2026-42311
(fixed in 12.2.0). Upgrading to Pillow 12.x requires validating
compatibility with rembg, realesrgan, mediapipe, and codeformer.
The BiRefNetHRMattingSession.predict normalization crashes when all
pixels share the same value (ma == mi). Use a guarded denominator so
uniform-alpha inputs produce a zero mask instead of a NaN explosion.
Also adds _register_birefnet_hr_matting() to install_feature.py so the
HR-matting model can be downloaded during feature installation, matching
the existing registration in remove_bg.py.
The desktop sidebar never rendered the custom logo because only mobile
views used the customLogo state. Added a logo section at the top of
the desktop sidebar that displays the custom logo (or the default
OtterLogo when none is set).
The upload handler used raw fetch() without checking response.ok, so
HTTP 4xx errors (e.g. file too large) were silently ignored and the UI
falsely reported success. Now checks response status and surfaces the
server error message.
Closes#125
The upscale function called runPythonWithProgress without a timeout parameter,
defaulting to the bridge's 10-minute hard limit. On CPU-only systems like
Synology NAS devices, Real-ESRGAN 4x upscaling easily exceeds this for modest
images. Additionally, when the timeout fired on the dispatcher path, the Python
process was left running and blocked all subsequent AI operations.
This fix adds an adaptive timeout based on input megapixels, scale factor, and
GPU availability (180s/effective-MP on CPU, 30s/effective-MP on GPU, floor of
10 minutes). It also kills the dispatcher on timeout so subsequent requests can
proceed via a fresh restart.
Closes#119