/** * Skia-based image decoder for getting RGBA pixel data. * Uses react-native-skia to decode images and extract pixel buffers. */ import { Skia, useImage, SkImage, } from "@shopify/react-native-skia"; /** * Decode a base64 PNG/JPEG image and return RGBA pixel data. * * @param base64 - Base64 encoded image data (without data URI prefix) * @returns RGBA pixel data with dimensions */ export function decodeImageBase64(base64: string): { pixels: Uint8Array; width: number; height: number; } | null { try { // Decode base64 to data const data = Skia.Data.fromBase64(base64); if (!data) return null; // Create image from data const image = Skia.Image.MakeImageFromEncoded(data); if (!image) return null; const width = image.width(); const height = image.height(); // Read pixels from the image // Note: Skia images are in RGBA format const pixels = image.readPixels(0, 0, { width, height, colorType: 4, // RGBA_8888 alphaType: 1, // Unpremultiplied }); if (!pixels) return null; return { pixels: new Uint8Array(pixels), width, height, }; } catch (error) { console.error("[SkiaDecoder] Failed to decode image:", error); return null; } } /** * Decode an image from a file URI and return RGBA pixel data. * * @param uri - File URI (e.g., file:///path/to/image.png) * @returns Promise with RGBA pixel data */ export async function decodeImageFromUri(uri: string): Promise<{ pixels: Uint8Array; width: number; height: number; } | null> { try { // Fetch the image data const response = await fetch(uri); const arrayBuffer = await response.arrayBuffer(); const base64 = arrayBufferToBase64(arrayBuffer); return decodeImageBase64(base64); } catch (error) { console.error("[SkiaDecoder] Failed to load image from URI:", error); return null; } } /** * Convert ArrayBuffer to base64 string. */ function arrayBufferToBase64(buffer: ArrayBuffer): string { let binary = ""; const bytes = new Uint8Array(buffer); const len = bytes.byteLength; for (let i = 0; i < len; i++) { binary += String.fromCharCode(bytes[i]); } return btoa(binary); } /** * React hook to decode an image from URI. * Uses Skia's useImage hook for caching. */ export function useDecodedImage(uri: string | null) { const skiaImage = useImage(uri); if (!skiaImage) { return { loading: true, pixels: null, width: 0, height: 0 }; } const width = skiaImage.width(); const height = skiaImage.height(); const pixels = skiaImage.readPixels(0, 0, { width, height, colorType: 4, // RGBA_8888 alphaType: 1, // Unpremultiplied }); return { loading: false, pixels: pixels ? new Uint8Array(pixels) : null, width, height, }; }