"use client"; import { useState, useRef, ChangeEvent, useEffect } from "react"; import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Button } from "@/components/ui/button"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"; import { Upload, Download, Image as ImageIcon, X, Trash2 } from "lucide-react"; import { toast } from "sonner"; import { cn } from "@/lib/utils"; export function ImageConverter() { const [images, setImages] = useState([]); const [previewUrls, setPreviewUrls] = useState([]); const [selectedImageIndex, setSelectedImageIndex] = useState( null ); const [width, setWidth] = useState(""); const [height, setHeight] = useState(""); const [format, setFormat] = useState<"png" | "jpeg" | "webp">("png"); const [isConverting, setIsConverting] = useState(false); const [isDraggingOver, setIsDraggingOver] = useState(false); const fileInputRef = useRef(null); useEffect(() => { // Clean up object URLs on component unmount return () => { previewUrls.forEach((url) => URL.revokeObjectURL(url)); }; }, [previewUrls]); useEffect(() => { if (selectedImageIndex !== null && previewUrls[selectedImageIndex]) { const img = new Image(); img.onload = () => { setWidth(img.width); setHeight(img.height); }; img.src = previewUrls[selectedImageIndex]; } else { setWidth(""); setHeight(""); } }, [selectedImageIndex, previewUrls]); const handleFiles = (files: FileList | null) => { if (!files || files.length === 0) return; const imageFiles = Array.from(files).filter((file) => file.type.startsWith("image/") ); if (imageFiles.length === 0) { toast.error("No valid image files found."); return; } const newImages = [...images, ...imageFiles]; const newPreviewUrls = [ ...previewUrls, ...imageFiles.map((file) => URL.createObjectURL(file)), ]; setImages(newImages); setPreviewUrls(newPreviewUrls); if (selectedImageIndex === null) { setSelectedImageIndex(images.length); } toast.success(`${imageFiles.length} image(s) added.`); }; const handleImageChange = (e: ChangeEvent) => { handleFiles(e.target.files); if (e.target) e.target.value = ""; }; const handleDragOver = (e: React.DragEvent) => { e.preventDefault(); setIsDraggingOver(true); }; const handleDragLeave = (e: React.DragEvent) => { e.preventDefault(); setIsDraggingOver(false); }; const handleDrop = (e: React.DragEvent) => { e.preventDefault(); setIsDraggingOver(false); handleFiles(e.dataTransfer.files); }; const handleRemoveImage = (indexToRemove: number) => { URL.revokeObjectURL(previewUrls[indexToRemove]); const newImages = images.filter((_, i) => i !== indexToRemove); const newPreviewUrls = previewUrls.filter((_, i) => i !== indexToRemove); setImages(newImages); setPreviewUrls(newPreviewUrls); if (selectedImageIndex === indexToRemove) { setSelectedImageIndex(newImages.length > 0 ? Math.max(0, indexToRemove - 1) : null); } else if (selectedImageIndex !== null && selectedImageIndex > indexToRemove) { setSelectedImageIndex(selectedImageIndex - 1); } }; const handleClearAll = () => { previewUrls.forEach((url) => URL.revokeObjectURL(url)); setImages([]); setPreviewUrls([]); setSelectedImageIndex(null); toast.info("All images cleared."); }; const handleConvertAndDownload = () => { if (selectedImageIndex === null || !width || !height) { toast.error("Please select an image and set dimensions."); return; } setIsConverting(true); const image = images[selectedImageIndex]; const previewUrl = previewUrls[selectedImageIndex]; const img = new Image(); img.crossOrigin = "anonymous"; img.src = previewUrl; 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 dataUrl = canvas.toDataURL(`image/${format}`); const link = document.createElement("a"); link.href = dataUrl; const originalName = image.name.substring(0, image.name.lastIndexOf('.')); link.download = `${originalName}_${width}x${height}.${format}`; document.body.appendChild(link); link.click(); document.body.removeChild(link); toast.success(`Exported ${image.name} successfully!`); } else { toast.error("Could not process the image."); } setIsConverting(false); }; img.onerror = () => { toast.error("Failed to load image for conversion."); setIsConverting(false); }; }; const hasImages = images.length > 0; const isImageSelected = selectedImageIndex !== null; return (
Image Settings Adjust resolution and format for the selected image.
setWidth(e.target.value)} disabled={!isImageSelected} />
setHeight(e.target.value)} disabled={!isImageSelected} />
{hasImages && (
Uploaded Images
{previewUrls.map((url, index) => (
))}
)}
{isImageSelected && previewUrls[selectedImageIndex] ? ( Selected image preview ) : (
fileInputRef.current?.click()}> Click or drag & drop images here
)}
); }