[dyad] Added individual image download - wrote 1 file(s)
This commit is contained in:
@@ -48,6 +48,7 @@ export function ImageConverter() {
|
||||
const [counterDigits, setCounterDigits] = useState<number>(3);
|
||||
|
||||
const [isConverting, setIsConverting] = useState(false);
|
||||
const [convertingIndex, setConvertingIndex] = useState<number | null>(null);
|
||||
const [isDraggingOver, setIsDraggingOver] = useState(false);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
@@ -204,6 +205,63 @@ export function ImageConverter() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleConvertAndDownloadSingle = async (index: number) => {
|
||||
if (!width || !height) {
|
||||
toast.error("Please set dimensions before downloading.");
|
||||
return;
|
||||
}
|
||||
|
||||
setConvertingIndex(index);
|
||||
toast.info(`Starting conversion for ${filenames[index]}...`);
|
||||
|
||||
const image = images[index];
|
||||
const previewUrl = previewUrls[index];
|
||||
|
||||
try {
|
||||
const img = new Image();
|
||||
img.crossOrigin = "anonymous";
|
||||
img.src = previewUrl;
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
img.onload = () => {
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = Number(width);
|
||||
canvas.height = Number(height);
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
if (ctx) {
|
||||
ctx.drawImage(img, 0, 0, Number(width), Number(height));
|
||||
const mimeType = `image/${format}`;
|
||||
const dataUrl = canvas.toDataURL(mimeType, format === 'png' ? undefined : quality / 100);
|
||||
const link = document.createElement("a");
|
||||
link.href = dataUrl;
|
||||
const finalFilename = generateFinalFilename(index);
|
||||
link.download = `${finalFilename}_${width}x${height}.${format}`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error(`Could not process ${image.name}.`));
|
||||
}
|
||||
};
|
||||
img.onerror = () => {
|
||||
reject(new Error(`Failed to load ${image.name} for conversion.`));
|
||||
};
|
||||
});
|
||||
|
||||
toast.success(`Successfully exported ${filenames[index]}!`);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
toast.error(error.message);
|
||||
} else {
|
||||
toast.error("An unknown error occurred during conversion.");
|
||||
}
|
||||
} finally {
|
||||
setConvertingIndex(null);
|
||||
}
|
||||
};
|
||||
|
||||
const hasImages = images.length > 0;
|
||||
|
||||
return (
|
||||
@@ -336,7 +394,7 @@ export function ImageConverter() {
|
||||
</Accordion>
|
||||
<Button
|
||||
onClick={handleConvertAndDownload}
|
||||
disabled={!hasImages || !width || !height || isConverting}
|
||||
disabled={!hasImages || !width || !height || isConverting || convertingIndex !== null}
|
||||
className="w-full"
|
||||
>
|
||||
<Download className="mr-2 h-4 w-4" />
|
||||
@@ -369,8 +427,8 @@ export function ImageConverter() {
|
||||
<div className="flex justify-between items-center">
|
||||
<CardTitle>Uploaded Images</CardTitle>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="ghost" size="sm" onClick={handleClearAll}><Trash2 className="mr-2 h-4 w-4" />Clear All</Button>
|
||||
<Button onClick={handleConvertAndDownload} disabled={!hasImages || !width || !height || isConverting}>
|
||||
<Button variant="ghost" size="sm" onClick={handleClearAll} disabled={isConverting || convertingIndex !== null}><Trash2 className="mr-2 h-4 w-4" />Clear All</Button>
|
||||
<Button onClick={handleConvertAndDownload} disabled={!hasImages || !width || !height || isConverting || convertingIndex !== null}>
|
||||
<Download className="mr-2 h-4 w-4" />
|
||||
{isConverting ? "Converting..." : `Download All (${images.length})`}
|
||||
</Button>
|
||||
@@ -395,10 +453,29 @@ export function ImageConverter() {
|
||||
Final name: {generateFinalFilename(index)}.{format}
|
||||
</p>
|
||||
</div>
|
||||
<Button variant="ghost" size="icon" className="shrink-0 text-gray-500 hover:text-destructive" onClick={() => handleRemoveImage(index)}>
|
||||
<div className="flex items-center shrink-0">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="text-gray-500 hover:text-primary"
|
||||
onClick={() => handleConvertAndDownloadSingle(index)}
|
||||
disabled={isConverting || convertingIndex !== null || !width || !height}
|
||||
title="Download this image"
|
||||
>
|
||||
<Download className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="shrink-0 text-gray-500 hover:text-destructive"
|
||||
onClick={() => handleRemoveImage(index)}
|
||||
disabled={isConverting || convertingIndex !== null}
|
||||
title="Remove this image"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
|
||||
Reference in New Issue
Block a user