import { useCallback } from 'react'; import { useCanvasStore, useLayerStore } from '@/store'; import { useHistoryStore } from '@/store/history-store'; import { openImageFile, exportCanvasAsImage, exportProject, loadProject, createCanvasFromDataURL, extractImageFromDataTransfer, isImageFile, isProjectFile, } from '@/lib/file-utils'; import type { Layer } from '@/types'; export function useFileOperations() { const { width, height, setDimensions } = useCanvasStore(); const { layers, createLayer, clearLayers } = useLayerStore(); const { clearHistory } = useHistoryStore(); /** * Create new image */ const createNewImage = useCallback( (newWidth: number, newHeight: number, backgroundColor: string) => { clearLayers(); clearHistory(); setDimensions(newWidth, newHeight); createLayer({ name: 'Background', width: newWidth, height: newHeight, fillColor: backgroundColor, }); }, [clearLayers, clearHistory, setDimensions, createLayer] ); /** * Open image file */ const openImage = useCallback( async (file: File) => { try { const img = await openImageFile(file); // Create new image with loaded dimensions clearLayers(); clearHistory(); setDimensions(img.width, img.height); // Create layer with loaded image const layer = createLayer({ name: file.name, width: img.width, height: img.height, }); if (layer.canvas) { const ctx = layer.canvas.getContext('2d'); if (ctx) { ctx.drawImage(img, 0, 0); } } } catch (error) { console.error('Failed to open image:', error); alert('Failed to open image file'); } }, [clearLayers, clearHistory, setDimensions, createLayer] ); /** * Open project file */ const openProject = useCallback( async (file: File) => { try { const projectData = await loadProject(file); clearLayers(); clearHistory(); setDimensions(projectData.width, projectData.height); // Recreate layers for (const layerData of projectData.layers) { const layer = createLayer({ name: layerData.name, width: layerData.width, height: layerData.height, opacity: layerData.opacity, blendMode: layerData.blendMode as any, }); // Load image data if (layerData.imageData && layer.canvas) { const canvas = await createCanvasFromDataURL( layerData.imageData, layerData.width, layerData.height ); const ctx = layer.canvas.getContext('2d'); if (ctx) { ctx.drawImage(canvas, 0, 0); } } } } catch (error) { console.error('Failed to open project:', error); alert('Failed to open project file'); } }, [clearLayers, clearHistory, setDimensions, createLayer] ); /** * Export current view as image */ const exportImage = useCallback( async (format: 'png' | 'jpeg' | 'webp', quality: number, filename: string) => { // Create temporary canvas with all layers const tempCanvas = document.createElement('canvas'); tempCanvas.width = width; tempCanvas.height = height; const ctx = tempCanvas.getContext('2d'); if (!ctx) return; // Draw all visible layers layers .filter((layer) => layer.visible && layer.canvas) .sort((a, b) => a.order - b.order) .forEach((layer) => { if (!layer.canvas) return; ctx.globalAlpha = layer.opacity; ctx.globalCompositeOperation = layer.blendMode as GlobalCompositeOperation; ctx.drawImage(layer.canvas, layer.x, layer.y); }); ctx.globalAlpha = 1; ctx.globalCompositeOperation = 'source-over'; await exportCanvasAsImage(tempCanvas, format, quality, filename); }, [layers, width, height] ); /** * Save project file */ const saveProject = useCallback( async (filename: string) => { await exportProject(layers, width, height, filename); }, [layers, width, height] ); /** * Handle file drop or paste */ const handleFileInput = useCallback( async (file: File) => { if (isProjectFile(file)) { await openProject(file); } else if (isImageFile(file)) { await openImage(file); } else { alert('Unsupported file type'); } }, [openProject, openImage] ); /** * Handle data transfer (drag & drop or paste) */ const handleDataTransfer = useCallback( async (dataTransfer: DataTransfer) => { const file = extractImageFromDataTransfer(dataTransfer); if (file) { await handleFileInput(file); } }, [handleFileInput] ); return { createNewImage, openImage, openProject, exportImage, saveProject, handleFileInput, handleDataTransfer, }; }