Commit Graph
491 Commits
Author SHA1 Message Date
SnapOtter 449f5dc97e fix: add exotic format decoding to image composition tool
The compose route only decoded HEIC/HEIF via ensureSharpCompat, causing
EPS, PSD, BMP, RAW, and other exotic formats to fail with
"Processing failed". Now uses the same full format pipeline as the
tool-factory for both base and overlay buffers.
2026-05-12 19:41:23 +08:00
SnapOtter d3d50c92be fix: update image info panel when navigating between files
Info panel always read files[0] and stored results in a single useState,
so it never changed when switching images. Now tracks selectedIndex,
auto-fetches on navigation after initial "Read Info" click, caches
results per-index, and aborts stale requests on rapid navigation.
2026-05-12 18:40:33 +08:00
SnapOtter da692e68b3 fix: wire up URL import to home page dropzone and prevent click-through
Pass onUrlImport handler through AppLayout to Dropzone so URL-imported
files are loaded on the home page. Add stopPropagation on the modal
overlay to prevent clicks from reaching elements underneath.
2026-05-11 23:35:26 +08:00
SnapOtter 7a2ea2069b fix: clean up crop mode toggle, extend timeouts for long-running tools
- Remove content-aware crop mode toggle from tool-page (now handled internally)
- Add content-aware-resize/crop to LONG_RUNNING_TOOLS for extended XHR timeout
- Remove unused onModeChange prop from CropProps
- Bump HEIC converter test timeouts to 60s to fix flaky failures
2026-05-11 22:48:05 +08:00
SnapOtter 095e3d9488 feat: add URL-based image import (single + bulk)
Add a fourth image ingestion path: importing images by URL.

Backend:
- POST /api/v1/fetch-urls endpoint with SSRF protection, image validation,
  preview generation, and p-queue concurrency
- SSRF utility blocking private IPs, validating redirect hops, with
  comprehensive IPv4/IPv6 range coverage

Frontend:
- Always-visible URL input in the dropzone for quick single-image import
- Bulk URL import modal with smart URL parsing (lists, markdown, HTML),
  per-URL progress tracking, retry on failure, and batch add
- useUrlImport hook managing the full fetch lifecycle

Tests: 48 new tests (23 SSRF unit, 10 URL parser unit, 15 integration)
2026-05-11 22:41:47 +08:00
SnapOtter b06906025c refactor: improve tool processing, dropzone, seam carving, and format encoding
- Refactor use-tool-processor and use-pipeline-processor hooks
- Enhance dropzone component with improved UX
- Improve seam carving with better error handling and tests
- Add JXL format encoding support to format-encoders
- Update tool routes for consistent format handling
- Add dropzone unit tests
2026-05-11 21:57:40 +08:00
SnapOtter b9272977df fix: add accessibility attributes to URL import modal 2026-05-11 21:43:54 +08:00
SnapOtter c901e29528 fix: address code review issues in useUrlImport hook 2026-05-11 21:34:43 +08:00
SnapOtter b7af25862a feat: add inline URL input to dropzone 2026-05-11 21:32:55 +08:00
SnapOtter d8941a2bc8 feat: add bulk URL import modal component 2026-05-11 21:32:40 +08:00
SnapOtter a85ca54feb refactor: remove redundant trim in URL parser 2026-05-11 21:28:24 +08:00
SnapOtter 4a430abf2f feat: add useUrlImport hook for URL fetch lifecycle 2026-05-11 21:27:43 +08:00
SnapOtter 9763a10db4 fix: add tool registry entry and manifest for content-aware-crop 2026-05-11 21:23:47 +08:00
SnapOtter a2be47bd68 feat: add smart URL parser for bulk import 2026-05-11 21:18:45 +08:00
SnapOtter 8ed0700a04 feat: add Content-Aware tab to crop settings with expansion controls 2026-05-11 21:15:03 +08:00
SnapOtter aa87c7e5e1 feat: add expansion preview for content-aware crop mode 2026-05-11 21:14:17 +08:00
SnapOtter 50d1f532d1 fix: block PDF uploads, fix PBM/PGM/PPM batch failures, add tests
- Added isImageFile() filter to all drop handlers (dropzone, collage,
  file-upload-area) so PDFs and non-image files are rejected on drop.
  Previously only the file picker's accept attribute filtered; drag-and-
  drop accepted anything.

- Added ppm, pgm, pbm to CLI_DECODED_FORMATS in file-validation.ts.
  These formats were missing, causing Sharp metadata checks to fail for
  some files during batch validation, which silently dropped them from
  results ("File not found in batch results").

- Added integration tests for PBM, PGM, PPM, TIFF, QOI, JP2, SVGZ
  single-file processing, plus a test confirming PDF is rejected.
2026-05-11 17:33:51 +08:00
SnapOtter a52a3b7e87 fix: generate server-side previews for all non-browser formats
SERVER_PREVIEW_EXTENSIONS was missing TIFF, DDS, DPX, EPS, FITS, JP2,
PBM/PGM/PPM, QOI, SVGZ, CUR, and many RAW variants. The server
already had decoders for all of them but the client never triggered
the preview fetch, so users saw "Preview not available" instead.
2026-05-11 17:25:26 +08:00
SnapOtter 1d7a7188bf fix: replace editor PenTool icon with image-edit icon
Custom SVG showing a landscape image frame with a pencil overlay,
clearly communicating "edit image" instead of the vector pen tool
which read more as Illustrator than Photoshop.
2026-05-11 17:20:14 +08:00
SnapOtter 0f1fd2050b fix: add +/- stepper buttons to quality slider in compress tool
Small bordered buttons with Minus/Plus icons flank the range slider,
allowing single-step quality adjustments. Disabled at min (1) and
max (100) boundaries.
2026-05-11 17:12:24 +08:00
SnapOtter aa614cb53d fix: constrain thumbnail strip to right pane and handle non-previewable formats
The thumbnail strip expanded beyond the right pane because the flex
section lacked min-w-0, causing a page-level horizontal scrollbar.
Added min-w-0 to both mobile and desktop image area sections.

For non-previewable formats (DDS, TIFF, EXR, PSD, RAW, etc.), show a
file info card with format and size instead of passing the blob URL to
an img tag that fails and shows an infinite "Loading preview..." spinner.
Also changed the ImageViewer error state from a misleading spinner to a
static "Preview not available" message.
2026-05-11 17:10:42 +08:00
SnapOtter aec1e91c5a fix: add .avif to all file picker accept strings
AVIF was missing from expandAccept() and every inline accept attribute,
causing the OS file picker to gray out .avif files. Drag-and-drop was
unaffected because it bypasses the accept filter. Added .avif to
dropzone.tsx expandAccept (covers all Dropzone pickers) plus 12 inline
accept strings across tool settings, pages, and file-upload-area.
2026-05-11 16:59:49 +08:00
SnapOtter 72de10b844 fix: clean up files section and add KB/MB unit selector to compress
- Remove duplicate "Files" heading (section header + inline count)
- Space "Show more" and "Clear all" apart on the same row
- Replace bare number input with number + KB/MB dropdown for target
  size, defaulting to KB; MB values are converted to KB for the API
- Hide native number input spin buttons for a cleaner look
2026-05-11 16:54:13 +08:00
SnapOtter 0c8e8c075c fix: remove checkerboard bleed in before-after slider and image viewer
The before-after slider hardcoded a checkerboard background on the
entire "after" overlay, which filled letterbox/pillarbox space around
non-transparent images. Replaced with a neutral bg-muted/30.

In image-viewer, moved the checkerboard from the outer container
(which included padding) to the img element itself, so it only
shows through transparent pixels rather than the surrounding area.
2026-05-11 16:48:51 +08:00
SnapOtter a7a17fbff4 fix: show all uploaded files with format and size in left panel
Replace the single-file pill with a full file list showing name
(truncated), format badge, and size for each file. First 5 files
are visible by default with a "show more" toggle for the rest.
Clicking a file selects it in the viewer. Applies to all tools.
2026-05-11 16:42:24 +08:00
SnapOtter 5b868886ba fix: make target size the primary compression mode
Move Target Size button to the left and default to it on load, since
it is the more useful mode for most users.
2026-05-11 16:33:10 +08:00
SnapOtter 172c0fa772 fix: update tool count to 51, refresh hero copy and login page
- Update stale tool counts (48/49/50) to 51 across all apps, docs, and tests
- Add Meme Generator to landing page bento grid (was missing)
- Add 12 SEO-friendly rotating phrases to hero typing cursor
- Change landing hero subtitle to "Every image tool you need."
- Replace outdated login page copy with branded hero + rotating phrases
2026-05-10 22:18:11 +08:00
SnapOtter caf351209b fix: upgrade favicons to 48x48 for Google Search visibility
Google requires favicons to be a multiple of 48px. The previous 32x32
favicon.png was being ignored, causing the generic globe icon in search
results. Adds favicon.ico (multi-size), apple-touch-icon, and fixes
og:image to use absolute URLs.
2026-05-10 21:49:56 +08:00
SnapOtter 78ca9720e7 fix: sync all workspace package versions to 1.16.0 2026-05-10 20:19:02 +08:00
SnapOtter 68fe02db35 fix: QA sweep -- settings dialog a11y, help button contrast, test expectation fixes
- Add role="dialog" and aria-modal="true" to settings dialog for screen
  reader compatibility and Playwright getByRole('dialog') selectors
- Fix sidebar Help button contrast ratio from 1.18:1 to WCAG AA compliant
  by using text-sidebar-foreground class
- Add explicit tabIndex={0} to search input for keyboard navigation
- Update convert test to expect BMP success (now a supported format)
- Fix watermark-image tiled test MIME type mismatch (webp not png)
- Swap compose test base/overlay so overlay is smaller than base
- Relax find-duplicates perceptual hash grouping assertions
2026-05-09 21:50:46 +08:00
SnapOtter 7f131d99a6 fix: QA sweep -- SSE crash, memory leaks, HEIC Docker decode, TGA detection, lint cleanup
- Fix SSE write-after-end crash in progress.ts (remove callback before ending stream)
- Fix blob URL memory leaks: revoke processedPreviewUrl and old HEIC preview URLs
- Add AbortController to batch fetch in use-tool-processor and use-pipeline-processor
- Fix TGA format misidentified as CUR (extension overrides magic bytes)
- Add libheif-plugin-libde265 to Docker for HEIC/HEIF decode support
- Remove unused imports and state (AppLayout, setSampledColor, useEffect)
- Fix non-null assertions in meme-text-renderer and meme-generator
- Fix confusing void type in meme-templates
- Remove unnecessary useEffect deps in adjustments-panel
- Fix Playwright strict mode violations in 5 E2E tests
2026-05-09 13:55:00 +08:00
SnapOtter ee871dc8ea feat: add Deep Enhance toggle to image enhancement UI
Toggle sends deepEnhance: true in settings to enable AI-powered
noise/artifact cleanup via SCUNet after the Sharp pipeline.
2026-05-09 11:31:36 +08:00
SnapOtter bdcfb6647c fix: sync frontend preset multipliers and fix sharpen type error
Add clahe and normalise entries to frontend PRESET_MULTIPLIERS to match
backend. Fix SharpenOptions to use m1 (not flat) per Sharp 0.34 types.
2026-05-09 11:26:49 +08:00
SnapOtter 96b055093b fix: magic wand tool selection, overlay, and mask consistency
- Replace naive 4-neighbor flood fill with scanline algorithm for performance
- Include alpha channel in color distance calculation
- Render actual mask outline with marching ants instead of bounding rectangle
- Use Konva Shape with batched canvas path for efficient edge rendering
- Add dedicated magicWandContiguous state (was incorrectly sharing fillContiguous)
- Add Contiguous checkbox to magic wand options bar
- Fix invertSelection to use consistent mask values (1 not 255) and expand
  inverted mask to full canvas dimensions instead of staying within old bounds
2026-05-09 00:14:57 +08:00
SnapOtter 05cb7c940f fix: deduplicate tool icons and add missing icon mappings
7 icons were shared by multiple tools, now each tool has a unique icon:
- favicon: Globe -> AppWindow
- smart-crop: Focus -> Crosshair
- noise-removal: Sparkles -> AudioLines
- beautify: Sparkles -> ImagePlus
- red-eye-removal: Eye -> ScanEye
- color-palette: Palette -> Droplets
- transparency-fixer: Wand2 -> ShieldCheck
- pdf-to-image: FileOutput -> BookImage

2 icons were missing from the ICON_MAP (falling back to generic FileImage):
- Scaling (content-aware-resize)
- Laugh (meme-generator)
2026-05-09 00:08:24 +08:00
SnapOtter e22ffa4ec9 fix: editor native layout, UI polish, meme templates auth, pipeline export, install queuing
- Remove editor from AppLayout so it owns the full viewport with no sidebar/padding
- Add back-arrow in menu bar for navigation, restyle menu bar to match native app feel
- Slim left toolbar from 48px to 36px with smaller icons and subtler dividers
- Fix options bar overlapping canvas via shrink-0 and overflow-hidden
- Fix opacity/blend controls clipping in right panel with min-w-0 on flex children
- Add global range slider CSS for consistent thin-track + round-thumb styling
- Make meme template routes public so img tags can load without Bearer auth
- Show pipeline export buttons in default compact view, not just expanded hover
- Queue individual AI feature installs instead of erroring when one is active
2026-05-08 23:30:27 +08:00
SnapOtter e3e5fd5890 Merge branch 'testing/image-editor' into main
Merges all image editor work: RAW decode improvements, expanded format
export (AVIF/TIFF/GIF/JXL/PSD), Photoshop-style menu bar, custom Konva
filters, smart guides, clone stamp, dodge/burn, eyedropper, pixel brush,
selection and transform tool overlays, autosave blob URL persistence,
and 49+ bug fixes across editor canvas and E2E tests.

# Conflicts:
#	apps/api/src/routes/tool-factory.ts
#	apps/api/src/routes/tools/convert.ts
#	apps/web/src/components/editor/common/export-dialog.tsx
#	apps/web/src/components/editor/editor-canvas.tsx
2026-05-08 21:37:52 +08:00
SnapOtter 0dbf300ef2 Merge branch 'feat/remotion-promo-videos'
# Conflicts:
#	pnpm-lock.yaml
2026-05-08 21:29:19 +08:00
SnapOtter 3a02affae3 feat: recover AVIF/TIFF/GIF/JXL/PSD export from orphaned commit
Recovers expanded export format support from orphaned commit 80961c01
and PSD export from b07ecd5. The editor export dialog now supports 7
formats (PNG, JPEG, WebP client-side; AVIF, TIFF, GIF, JXL via server
conversion). PSD export uses ImageMagick on the backend.
2026-05-08 21:06:29 +08:00
SnapOtter 7d7df194bc feat: add pipeline import from JSON file
Add import button to saved pipelines section with file picker,
validation, and error display with auto-dismiss. Section now
always renders with empty state text when no pipelines exist.
2026-05-08 20:59:25 +08:00
SnapOtter e5939f7b5a feat: add pipeline export as JSON file 2026-05-08 20:55:48 +08:00
SnapOtter 321c5da998 fix: menu bar dropdown transparent background, move test to e2e-editor
- Replace bg-popover with bg-card for dropdown backgrounds (popover CSS
  variable is not defined in this project's theme)
- Move menu bar test to tests/e2e-editor/ and adapt for editorPage fixture
- Fix click-outside test to handle welcome screen overlay
2026-05-08 20:47:05 +08:00
SnapOtter 5c64581496 feat: recover Photoshop-style menu bar from orphaned branch
Recovers the editor menu bar (File/Edit/Image/Layer/Select/Filter/View)
from orphaned commit b07ecd5 that was lost during a rebase. Integrates
it into the current editor-page layout with PSD/TGA/EXR/HDR file open
support and new document dialog.
2026-05-08 20:37:26 +08:00
SnapOtter a1a71e507f fix: 8 image editor bugs found during Docker-based E2E testing
- fix WebP export silently producing PNG when background is non-transparent
- fix autosave not converting blob: URLs inside image-type canvas objects
- fix project load not resetting selection/crop/clipboard state
- fix rotateCanvas not updating object rotation attributes
- fix flipCanvas not negating object rotation attributes
- fix line shadow props overridden by effect spread ordering
- fix "outside" stroke position rendering same as "center"
- add missing pencil tool keyboard shortcut (N)
- remove misleading resample dropdown from image resize dialog
- fix E2E autosave tests for production builds (no Vite dynamic imports)
- fix color picker test case sensitivity (CSS uppercase vs DOM text)
- add 4 unit tests for rotation attribute transforms
2026-05-08 20:27:06 +08:00
SnapOtter aa773addb4 merge: resolve conflict with main branch in tool-registry.tsx 2026-05-08 18:55:28 +08:00
SnapOtter dac30f14f0 fix(meme-generator): match preview and server render text sizing
- Preview font size now calculated from actual container width, not viewport
- Preview stroke scales proportionally with font size (4% ratio)
- Server stroke reduced from 6% to 4% to match preview
- Added ResizeObserver to track container width for accurate sizing
- Added paint-order: stroke fill to CSS preview for consistent rendering
2026-05-08 18:17:17 +08:00
SnapOtter 0c1980c6db fix(meme-generator): cap auto font size, center text vertically, fix sidebar truncation
- Auto font size now capped at min(200, boxHeight/2, boxWidth/3) to prevent
  oversized text on server render
- Text vertically centered within each text box
- Sidebar color labels shortened (Text/Stroke) with min-w-0 to prevent overflow
2026-05-08 17:42:04 +08:00
SnapOtter 66dfad8122 fix(meme-generator): fix preview collapse from inline-block + container query
The containerType: inline-size CSS containment prevented the image from
expanding its parent container, causing the preview to render at 0x0px.
Removed inline-block and containerType, switched font sizing to vw units.
2026-05-08 17:38:12 +08:00
SnapOtter e118717337 merge: resolve conflict with main branch in README.md 2026-05-08 17:32:16 +08:00
SnapOtter 68ed34ec29 fix(meme-generator): split into settings + preview panels with shared Zustand store
The meme generator had everything in one component crammed into the
narrow right sidebar. This splits it into the proper two-panel
architecture (like collage/qr-generate):

- meme-store.ts: shared Zustand store for all meme state and actions
- meme-generator-preview.tsx: ResultsPanel (main area) with gallery,
  layout picker, editor preview with CSS text overlay, and result view
- meme-generator-settings.tsx: Settings sidebar with text inputs, font
  picker, colors, alignment, and generate button
- tool-registry.tsx: adds ResultsPanel to the meme-generator entry

Also fixes text overlay sizing (reduced from 0.6cqi to 0.45cqi with
smaller stroke width) and moves font injection to a standalone function
callable from either component.
2026-05-08 17:15:06 +08:00