import { useCallback, useRef, useEffect, useState, useReducer } from 'react' export function useImageLoader() { const fileInputRef = useRef(null) const loadImage = useCallback( (file: File): Promise<{ image: HTMLImageElement; imageData: ImageData }> => { return new Promise((resolve, reject) => { const url = URL.createObjectURL(file) const img = new Image() img.onload = () => { const canvas = document.createElement('canvas') canvas.width = img.width canvas.height = img.height const ctx = canvas.getContext('2d') if (!ctx) { URL.revokeObjectURL(url) reject(new Error('Failed to get canvas context')) return } ctx.drawImage(img, 0, 0) const imageData = ctx.getImageData(0, 0, img.width, img.height) URL.revokeObjectURL(url) resolve({ image: img, imageData }) } img.onerror = () => { URL.revokeObjectURL(url) reject(new Error('Failed to load image')) } img.src = url }) }, [] ) const openFileDialog = useCallback(() => { fileInputRef.current?.click() }, []) const handleFileSelect = useCallback( (event: React.ChangeEvent, onLoad: (data: { image: HTMLImageElement; imageData: ImageData }) => void) => { const file = event.target.files?.[0] if (!file) return if (!file.type.startsWith('image/')) { alert('Please select an image file') return } loadImage(file).then(onLoad).catch((error) => { alert(`Failed to load image: ${error.message}`) }) }, [loadImage] ) return { fileInputRef, loadImage, openFileDialog, handleFileSelect, } } export function useDragAndDrop(onLoad: (image: HTMLImageElement, imageData: ImageData) => void) { const [isDragging, setIsDragging] = useState(false) const loadImageFromFile = useCallback( (file: File): Promise<{ image: HTMLImageElement; imageData: ImageData }> => { return new Promise((resolve, reject) => { const url = URL.createObjectURL(file) const img = new Image() img.onload = () => { const canvas = document.createElement('canvas') canvas.width = img.width canvas.height = img.height const ctx = canvas.getContext('2d') if (!ctx) { URL.revokeObjectURL(url) reject(new Error('Failed to get canvas context')) return } ctx.drawImage(img, 0, 0) const imageData = ctx.getImageData(0, 0, img.width, img.height) URL.revokeObjectURL(url) resolve({ image: img, imageData }) } img.onerror = () => { URL.revokeObjectURL(url) reject(new Error('Failed to load image')) } img.src = url }) }, [] ) const handleDragOver = useCallback((e: React.DragEvent) => { e.preventDefault() e.stopPropagation() setIsDragging(true) }, []) const handleDragLeave = useCallback((e: React.DragEvent) => { e.preventDefault() e.stopPropagation() setIsDragging(false) }, []) const handleDrop = useCallback( async (e: React.DragEvent) => { e.preventDefault() e.stopPropagation() setIsDragging(false) const file = e.dataTransfer.files[0] if (!file || !file.type.startsWith('image/')) return try { const { image, imageData } = await loadImageFromFile(file) onLoad(image, imageData) } catch (error) { alert(`Failed to load image: ${error instanceof Error ? error.message : 'Unknown error'}`) } }, [onLoad, loadImageFromFile] ) return { handleDragOver, handleDragLeave, handleDrop, isDragging, } }