[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 [counterDigits, setCounterDigits] = useState<number>(3);
|
||||||
|
|
||||||
const [isConverting, setIsConverting] = useState(false);
|
const [isConverting, setIsConverting] = useState(false);
|
||||||
|
const [convertingIndex, setConvertingIndex] = useState<number | null>(null);
|
||||||
const [isDraggingOver, setIsDraggingOver] = useState(false);
|
const [isDraggingOver, setIsDraggingOver] = useState(false);
|
||||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
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;
|
const hasImages = images.length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -336,7 +394,7 @@ export function ImageConverter() {
|
|||||||
</Accordion>
|
</Accordion>
|
||||||
<Button
|
<Button
|
||||||
onClick={handleConvertAndDownload}
|
onClick={handleConvertAndDownload}
|
||||||
disabled={!hasImages || !width || !height || isConverting}
|
disabled={!hasImages || !width || !height || isConverting || convertingIndex !== null}
|
||||||
className="w-full"
|
className="w-full"
|
||||||
>
|
>
|
||||||
<Download className="mr-2 h-4 w-4" />
|
<Download className="mr-2 h-4 w-4" />
|
||||||
@@ -369,8 +427,8 @@ export function ImageConverter() {
|
|||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<CardTitle>Uploaded Images</CardTitle>
|
<CardTitle>Uploaded Images</CardTitle>
|
||||||
<div className="flex items-center gap-2">
|
<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 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}>
|
<Button onClick={handleConvertAndDownload} disabled={!hasImages || !width || !height || isConverting || convertingIndex !== null}>
|
||||||
<Download className="mr-2 h-4 w-4" />
|
<Download className="mr-2 h-4 w-4" />
|
||||||
{isConverting ? "Converting..." : `Download All (${images.length})`}
|
{isConverting ? "Converting..." : `Download All (${images.length})`}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -395,9 +453,28 @@ export function ImageConverter() {
|
|||||||
Final name: {generateFinalFilename(index)}.{format}
|
Final name: {generateFinalFilename(index)}.{format}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</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">
|
||||||
<X className="h-4 w-4" />
|
<Button
|
||||||
</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>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user