mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat: full HEIF/HEIC support, content-aware resize performance fix, UI improvements
- Add bidirectional HEIF support: decode (input) and encode (output) via system heif-convert/heif-enc - Add server-side WebP preview generation for non-browser-previewable formats (HEIC, TIFF) - Fix content-aware resize failing on HEIF input (decode before passing to caire) - Fix content-aware resize timeout on large images by downscaling to max 1200px and using JPEG intermediate - Add HEIF as target format in convert tool - Add loading spinner for HEIF preview decode in file store - Fix file picker not accepting HEIF files (explicit .heic,.heif,.hif extensions) - Extend frontend timeout for medium tools to 180s with 45s progress animation - Redesign rotate controls with preset buttons and compact flip section - Remove misleading savings percentage from convert tool
This commit is contained in:
@@ -7,6 +7,7 @@ import { useFileStore } from "@/stores/file-store";
|
||||
interface ProcessResult {
|
||||
jobId: string;
|
||||
downloadUrl: string;
|
||||
previewUrl?: string;
|
||||
originalSize: number;
|
||||
processedSize: number;
|
||||
savedFileId?: string;
|
||||
@@ -31,7 +32,7 @@ const AI_PYTHON_TOOLS = new Set<string>(PYTHON_SIDECAR_TOOLS);
|
||||
|
||||
// Tools that take a few seconds (not instant like Sharp, not minutes like AI).
|
||||
// Uses a smoother progress: upload 0-40%, then a gradual fill during processing.
|
||||
const MEDIUM_TOOLS = new Set(["content-aware-resize"]);
|
||||
const MEDIUM_TOOLS = new Set(["content-aware-resize", "convert"]);
|
||||
|
||||
export function useToolProcessor(toolId: string) {
|
||||
const {
|
||||
@@ -141,8 +142,8 @@ export function useToolProcessor(toolId: string) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhrRef.current = xhr;
|
||||
|
||||
// Timeout: 60s for fast/medium tools, 5 min for AI tools
|
||||
xhr.timeout = isAiTool ? 300_000 : 60_000;
|
||||
// Timeout: 60s for fast tools, 3 min for medium (seam carving), 5 min for AI
|
||||
xhr.timeout = isAiTool ? 300_000 : isMediumTool ? 180_000 : 60_000;
|
||||
|
||||
// For AI tools: upload = 0-15%, processing = 15-100% (SSE-driven)
|
||||
// For medium tools: upload = 0-40%, processing = 40-95% (gradual fill)
|
||||
@@ -167,11 +168,11 @@ export function useToolProcessor(toolId: string) {
|
||||
stage: isAiTool ? "Starting..." : "Processing...",
|
||||
}));
|
||||
|
||||
// Medium tools: gradually fill from upload weight to 95% over ~15s
|
||||
// Medium tools: gradually fill from upload weight to 95% over ~45s
|
||||
if (isMediumTool) {
|
||||
const start = UPLOAD_WEIGHT;
|
||||
const target = 95;
|
||||
const step = (target - start) / 30; // 30 ticks over ~15s
|
||||
const step = (target - start) / 90; // 90 ticks over ~45s
|
||||
processingTimerRef.current = setInterval(() => {
|
||||
setProgress((prev) => {
|
||||
if (prev.phase !== "processing") return prev;
|
||||
@@ -194,7 +195,7 @@ export function useToolProcessor(toolId: string) {
|
||||
try {
|
||||
const result: ProcessResult = JSON.parse(xhr.responseText);
|
||||
setJobId(result.jobId);
|
||||
setProcessedUrl(result.downloadUrl);
|
||||
setProcessedUrl(result.downloadUrl, result.previewUrl);
|
||||
setSizes(result.originalSize, result.processedSize);
|
||||
// Update serverFileId if a new version was saved
|
||||
if (result.savedFileId) {
|
||||
|
||||
Reference in New Issue
Block a user