import { useCallback, useMemo } from 'react' import { useAppStore } from '@/store' import { computeConvolutionStep, getPixel } from '@/lib/convolution/engine' import type { ImageDataExtended, ConvolutionStep, PaddingMode } from '@/types' export function useStaticConvolution() { const { originalImageData, selectedKernel, customKernelMatrix, customKernelNormalize, settings, } = useAppStore() const kernel = selectedKernel?.matrix ?? customKernelMatrix const normalize = selectedKernel?.normalize ?? customKernelNormalize const padding = settings.padding // Create extended image data for the engine const extendedImage = useMemo((): ImageDataExtended | null => { if (!originalImageData) return null return { data: originalImageData.data, width: originalImageData.width, height: originalImageData.height, channels: 4, } }, [originalImageData]) const computeStep = useCallback( (x: number, y: number, channel: number = 0): ConvolutionStep | null => { if (!extendedImage || !kernel) return null // Clamp coordinates to valid range const clampedX = Math.max(0, Math.min(x, extendedImage.width - 1)) const clampedY = Math.max(0, Math.min(y, extendedImage.height - 1)) const clampedChannel = Math.max(0, Math.min(channel, extendedImage.channels - 1)) return computeConvolutionStep(extendedImage, kernel, padding, normalize, clampedX, clampedY, clampedChannel) }, [extendedImage, kernel, padding, normalize] ) const getPixelValue = useCallback( (x: number, y: number, channel: number = 0): number => { if (!extendedImage) return 0 const clampedX = Math.max(0, Math.min(x, extendedImage.width - 1)) const clampedY = Math.max(0, Math.min(y, extendedImage.height - 1)) const clampedChannel = Math.max(0, Math.min(channel, extendedImage.channels - 1)) return getPixel(extendedImage, clampedX, clampedY, clampedChannel, padding) }, [extendedImage, padding] ) const getPaddedImagePreview = useCallback( (kernelSize: number): { width: number; height: number; data: number[] } | null => { if (!extendedImage) return null const halfKernel = Math.floor(kernelSize / 2) const paddedWidth = extendedImage.width + 2 * halfKernel const paddedHeight = extendedImage.height + 2 * halfKernel const data: number[] = [] for (let py = 0; py < paddedHeight; py++) { for (let px = 0; px < paddedWidth; px++) { const origX = px - halfKernel const origY = py - halfKernel // Sample each channel for (let c = 0; c < Math.min(3, extendedImage.channels); c++) { data.push(getPixel(extendedImage, origX, origY, c, padding)) } // Alpha channel if (extendedImage.channels > 3) { data.push(getPixel(extendedImage, origX, origY, 3, padding)) } } } return { width: paddedWidth, height: paddedHeight, data } }, [extendedImage, padding] ) return { computeStep, getPixelValue, getPaddedImagePreview, kernel, normalize, padding, imageWidth: extendedImage?.width ?? 0, imageHeight: extendedImage?.height ?? 0, imageChannels: extendedImage?.channels ?? 0, hasImage: !!extendedImage, hasKernel: !!kernel, } }