The ImageDecoder class decodes compressed image data (JPEG, PNG, WebP, GIF, AVIF) into VideoFrame objects that can be processed, edited, or re-encoded.
import { ImageDecoder } from 'node-webcodecs';import { readFileSync } from 'fs';// Read image fileconst imageData = readFileSync('photo.jpg');// Create decoderconst decoder = new ImageDecoder({ data: imageData, type: 'image/jpeg',});// Wait for image to be fully parsedawait decoder.completed;// Decode the imageconst result = await decoder.decode();const frame = result.image;console.log(`Decoded ${frame.codedWidth}x${frame.codedHeight} image`);// Process the frame...// IMPORTANT: Always close frames when doneframe.close();decoder.close();
Always call frame.close() on decoded imagesDecoded VideoFrame objects hold native memory that is not tracked by JavaScript’s garbage collector. Forgetting to close frames will cause memory leaks.
Copy
// Goodconst result = await decoder.decode();processFrame(result.image);result.image.close(); // Release memory// Bad - memory leak!const result = await decoder.decode();processFrame(result.image);// Forgot to close!
Whether all image data has been received and parsed.For images loaded from a Buffer, this is true immediately after construction.
For images loaded from a ReadableStream, this becomes true when the stream ends.
const decoder = new ImageDecoder({ data: imageBuffer, type: 'image/jpeg',});const result = await decoder.decode();console.log(`Decoded: ${result.image.codedWidth}x${result.image.codedHeight}`);console.log(`Complete: ${result.complete}`);result.image.close();
Example: Animated GIF frame extraction
Copy
import { ImageDecoder } from 'node-webcodecs';import { readFileSync } from 'fs';async function extractGifFrames(gifPath: string) { const gifData = readFileSync(gifPath); const decoder = new ImageDecoder({ data: gifData, type: 'image/gif', }); await decoder.completed; const frames = []; let frameIndex = 0; while (true) { try { const result = await decoder.decode({ frameIndex }); // Clone the frame if you need to keep it after decoding more frames const frameClone = result.image.clone(); frames.push(frameClone); // Close the original result.image.close(); console.log(`Extracted frame ${frameIndex}: ${frameClone.codedWidth}x${frameClone.codedHeight}`); // Check if this was the last frame if (result.complete) { break; } frameIndex++; } catch (error) { // No more frames break; } } console.log(`Extracted ${frames.length} frames from GIF`); // Process frames... // Clean up frames.forEach(frame => frame.close()); decoder.close(); return frames.length;}extractGifFrames('animation.gif');
Whether to only return complete frames. When true, the promise will not resolve until the frame is fully decoded. When false, partial frames may be returned for progressive images.
Returns:Promise<ImageDecodeResult> - Resolves to an object containing the decoded frame