import { Download } from "lucide-react"; import { useState } from "react"; import { ProgressCard } from "@/components/common/progress-card"; import { useTranslation } from "@/contexts/i18n-context"; import { useToolProcessor } from "@/hooks/use-tool-processor"; import { format } from "@/lib/format"; import { useFileStore } from "@/stores/file-store"; type ColorMode = "bw" | "color"; type PathMode = "none" | "polygon" | "spline"; type Detail = "low" | "medium" | "high"; type Preset = "logo" | "illustration" | "photo" | "sketch" | "custom"; interface VectorizeState { colorMode: ColorMode; threshold: number; colorPrecision: number; layerDifference: number; filterSpeckle: number; pathMode: PathMode; cornerThreshold: number; invert: boolean; } const PRESET_SETTINGS: Record, VectorizeState> = { logo: { colorMode: "bw", threshold: 128, colorPrecision: 6, layerDifference: 6, filterSpeckle: 2, pathMode: "spline", cornerThreshold: 60, invert: false, }, illustration: { colorMode: "color", threshold: 128, colorPrecision: 4, layerDifference: 16, filterSpeckle: 8, pathMode: "spline", cornerThreshold: 60, invert: false, }, photo: { colorMode: "color", threshold: 128, colorPrecision: 8, layerDifference: 5, filterSpeckle: 4, pathMode: "spline", cornerThreshold: 60, invert: false, }, sketch: { colorMode: "bw", threshold: 100, colorPrecision: 6, layerDifference: 6, filterSpeckle: 1, pathMode: "polygon", cornerThreshold: 60, invert: false, }, }; const DETAIL_TO_SPECKLE: Record = { low: 16, medium: 4, high: 1 }; function speckleToDetail(speckle: number): Detail { if (speckle >= 10) return "low"; if (speckle >= 3) return "medium"; return "high"; } export function VectorizeSettings() { const { t } = useTranslation(); const { files } = useFileStore(); const { processFiles, processAllFiles, processing, error, downloadUrl, originalSize, processedSize, progress, } = useToolProcessor("vectorize"); const [preset, setPreset] = useState("logo"); const [colorMode, setColorMode] = useState("bw"); const [threshold, setThreshold] = useState(128); const [colorPrecision, setColorPrecision] = useState(6); const [layerDifference, setLayerDifference] = useState(6); const [filterSpeckle, setFilterSpeckle] = useState(2); const [pathMode, setPathMode] = useState("spline"); const [cornerThreshold, setCornerThreshold] = useState(60); const [invert, setInvert] = useState(false); const applyPreset = (p: Preset) => { setPreset(p); if (p === "custom") return; const s = PRESET_SETTINGS[p]; setColorMode(s.colorMode); setThreshold(s.threshold); setColorPrecision(s.colorPrecision); setLayerDifference(s.layerDifference); setFilterSpeckle(s.filterSpeckle); setPathMode(s.pathMode); setCornerThreshold(s.cornerThreshold); setInvert(s.invert); }; const updateSetting = (setter: (v: T) => void) => { return (v: T) => { setPreset("custom"); setter(v); }; }; const handleProcess = () => { const settings = { colorMode, threshold, colorPrecision, layerDifference, filterSpeckle, pathMode, cornerThreshold, invert, }; if (files.length > 1) { processAllFiles(files, settings); } else { processFiles(files, settings); } }; const hasFile = files.length > 0; const detail = speckleToDetail(filterSpeckle); return (
{/* Preset */}

Preset

{(["logo", "illustration", "photo"] as const).map((p) => ( ))}
{(["sketch", "custom"] as const).map((p) => ( ))}
{/* Color Mode */}

Color Mode

{(["bw", "color"] as const).map((m) => ( ))}
{/* Color-specific settings */} {colorMode === "color" && ( <>
{colorPrecision}
updateSetting(setColorPrecision)(Number(e.target.value))} className="w-full mt-1" />
Fewer colors More colors
{layerDifference}
updateSetting(setLayerDifference)(Number(e.target.value))} className="w-full mt-1" />
Smooth gradients Flat colors
)} {/* B&W-specific settings */} {colorMode === "bw" && (
{threshold}
updateSetting(setThreshold)(Number(e.target.value))} className="w-full mt-1" />
More white More black
)}
{/* Detail */}

Detail

{(["low", "medium", "high"] as const).map((d) => ( ))}
{/* Smoothing */}

Smoothing

{(["none", "polygon", "spline"] as const).map((m) => ( ))}
{/* Corner Threshold (color mode) */} {colorMode === "color" && (
{cornerThreshold}deg
updateSetting(setCornerThreshold)(Number(e.target.value))} className="w-full mt-1" />
More corners Smoother
)} {/* Invert toggle */}
Invert Colors
{/* Error */} {error &&

{error}

} {/* Size info */} {originalSize != null && processedSize != null && (

Original: {(originalSize / 1024).toFixed(1)} KB

SVG: {(processedSize / 1024).toFixed(1)} KB

)} {/* Submit */} {processing ? ( ) : ( )} {/* Download */} {downloadUrl && ( Download SVG )}
); }