Commit Graph
1223 Commits
Author SHA1 Message Date
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 56e8cf7352 fix: add exotic format decoding to image-to-pdf tool
The image-to-pdf route used ensureSharpCompat (HEIC-only) instead of the
full format decode pipeline from tool-factory. Formats like FITS, PSD,
RAW, EXR, HDR, TGA, etc. passed through undecoded and crashed Sharp.

Replace with validateImageBuffer + decodeToSharpCompat to match the
standard tool pipeline.
2026-05-11 22:47:10 +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 04e7b21f31 test: improve coverage for URL import feature 2026-05-11 22:39:37 +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 1f008d9bcb test: add E2E smoke tests for URL import UI 2026-05-11 21:37:19 +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 656a8d3d44 test: add Playwright E2E tests for content-aware-crop 2026-05-11 21:32:46 +08:00
SnapOtter d8941a2bc8 feat: add bulk URL import modal component 2026-05-11 21:32:40 +08:00
SnapOtter 4a9cc715f2 fix: deduplicate filenames in fetch-urls to prevent overwrites
All URLs in a batch share a single workspace directory. When multiple
URLs resolve to the same filename (e.g. two different domains both
serving photo.jpg), the second writeFile silently overwrites the first.

Track used filenames in a Set and append _1, _2, etc. on collision,
mirroring the existing getUniqueName pattern from batch.ts.
2026-05-11 21:32:27 +08:00
SnapOtter 485a2d72d3 fix: harden SSRF validation with missing IP ranges and safeFetch tests 2026-05-11 21:29:58 +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 d38101b8ea feat: add POST /api/v1/fetch-urls endpoint for server-side URL import
Accepts { urls: string[] } (1-50), fetches each URL with SSRF protection
via safeFetch, validates as image, saves to workspace, generates WebP
preview for non-browser formats, and returns results with download URLs.
Uses p-queue with concurrency 4 to parallelize fetches.
2026-05-11 21:24:56 +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 488ed95686 feat: add SSRF validation utility for URL fetch 2026-05-11 21:18:23 +08:00
SnapOtter 32faee9578 test: add integration tests for content-aware-crop endpoint 2026-05-11 21:16:50 +08:00
SnapOtter b1d189d325 test: add unit tests for outpainting bridge 2026-05-11 21:16:35 +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 694cc86aff feat: add content-aware-crop API route with async SSE processing 2026-05-11 21:12:00 +08:00
SnapOtter 347b8ad530 feat: register content-aware-crop in shared package 2026-05-11 21:08:30 +08:00
SnapOtter 4a863e1ce8 feat: add Node bridge for outpainting 2026-05-11 21:08:08 +08:00
SnapOtter 9466df90e0 fix: extract first frame from multi-image FITS files
ImageMagick outputs numbered files (fits-out-0.png, fits-out-1.png)
for multi-image FITS, but decodeFits expected a single output file.
Added [0] selector to extract only the first frame, matching the
pattern used by DDS and PSD decoders.
2026-05-11 18:13:29 +08:00
SnapOtter 2acf0ea48a fix: fall back to Sharp when CLI decoders are unavailable
DNG and FITS previews showed "Preview not available" because their CLI
decoders (ExifTool/ImageMagick) were not installed. Sharp can read both
formats natively (DNG is TIFF-based, FITS via libvips fitsload).

Added Sharp fallback to the preview endpoint, batch processing, and
tool factory: when decodeToSharpCompat throws, try sharp(buffer).metadata()
before returning 422. If Sharp can read the buffer, processing continues
without the CLI decoder.
2026-05-11 18:00:59 +08:00
SnapOtter 7d9612784e test: expand exotic format coverage across batch, validation, and detection
Batch processing (batch.test.ts):
- 15 format tests (PBM, PGM, PPM, TIFF, QOI, JP2, SVGZ, DDS, DPX, EPS,
  TGA, PSD, HDR, ICO, CUR) verifying batch compress produces valid ZIP
- 2 delegate-dependent tests (FITS, EXR) that accept 200 or 422
- Mixed-format batch test (PBM + TIFF + QOI in one request)

Validation (utilities.test.ts):
- 15 new tests for validateImageBuffer covering PBM, PGM, PPM, DDS, DPX,
  FITS, JP2, QOI, SVGZ, EPS, CUR, HEIF, APNG, DNG + PDF rejection

Format detection (detect.test.ts):
- 8 fixture-based detection tests (PPM, DNG, JP2, SVGZ, PBM, PGM, HDR, TGA)
- 4 synthetic magic byte tests (PPM P3/P6, JP2 box, J2K codestream)
2026-05-11 17:45:42 +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 5b5767990b fix: tighten target-size compression tolerance from 5% to 1%
The binary search exited early at 5% tolerance, producing output like
48.3KB for a 50KB target. Reducing to 1% with 12 iterations makes the
output much closer to the requested target.
2026-05-11 16:29:14 +08:00
SnapOtter e6a35265ef fix: target-size compression now respects the target
The binary search found the right quality but sharp(buffer).toBuffer()
re-encoded at default quality 80, inflating the output (e.g. 50KB target
producing 90KB). Replaced buffer-wrapping with proper Sharp pipelines
that include .toFormat() with the proven quality. Also added progressive
dimension reduction when quality alone cannot reach the target, and
tightened tolerance to only accept at-or-below-target results.
2026-05-11 16:19:40 +08:00
SnapOtter 69597f3c39 fix: consolidate images into branding directory
Move dashboard screenshots to branding/, remove redundant images/
directory, and update all references in README and CI workflow.
2026-05-11 14:57:53 +08:00
SnapOtter 8598808b3c fix: correct repository name casing in clone instructions 2026-05-10 22:41:52 +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 32e7b03ab4 fix: add remotion directory to .gitignore 2026-05-10 21:53:16 +08:00
SnapOtter 28f919b5d7 fix: add favicon to landing page for Google Search visibility
The landing page had no favicon at all, causing Google to show a
generic globe icon in search results for snapotter.com.
2026-05-10 21:50:56 +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 8aa5d9a5f2 Add new branding SVG files for wordmark in white and default colors
- Created wordmark-white.svg with white text for branding use.
- Created wordmark.svg with dark text for branding use.
2026-05-10 21:25:43 +08:00
SnapOtter 78ca9720e7 fix: sync all workspace package versions to 1.16.0 2026-05-10 20:19:02 +08:00
SnapOtter 86a74ab706 fix: replace hardcoded version in deployment docs with placeholder 2026-05-10 20:17:40 +08:00