Efficient JavaScript GIF Parser and Decoder
gifuct-js is a lean and efficient JavaScript library specifically designed for parsing and decoding GIF files. It aims to overcome the inefficiencies and complexities found in older GIF processing libraries by providing a streamlined API focused solely on extracting raw frame data. The current stable version is 2.1.2, last updated in November 2021. The library prioritizes performance, making it suitable for resource-constrained environments like mobile hybrid applications, as exemplified by its original development for the Ruffle project. It operates by consuming GIF files as `Uint8Array` buffers and leverages `js-binary-schema-parser` internally for robust parsing. A key differentiator is its 'decode-only' approach; unlike many alternatives, it deliberately omits any built-in drawing or rendering logic, empowering developers to integrate GIF data with their preferred rendering engines (e.g., Canvas, WebGL). While it can optionally generate canvas-ready `Uint8ClampedArray` patches, it leaves full control over animation and display to the implementer. The project maintains a stable release cadence, with updates primarily focusing on parsing accuracy and performance enhancements rather than frequent new feature introductions.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'length')
cause `parseGIF` received an invalid or malformed `ArrayBuffer`, or an object that is not an `ArrayBuffer`.fixVerify that the input `ArrayBuffer` is correctly loaded from a valid GIF file and is indeed an `ArrayBuffer` type. Log the input to `parseGIF` to inspect its type and content before passing it. -
ReferenceError: parseGIF is not defined
cause Incorrect ES Module import syntax or attempting to use CommonJS `require` in an ES Module context (or vice versa).fixFor modern JavaScript environments (ESM), use `import { parseGIF, decompressFrames } from 'gifuct-js'`. For CommonJS (Node.js <14 or specific setups), use `const { parseGIF, decompressFrames } = require('gifuct-js')`. -
Canvas shows wrong colors/transparency or 'blurry' frames after decompression.
cause Misunderstanding `patch` vs `pixels` data, incorrect handling of `disposalType`, or transparency issues when drawing frames, especially when `buildPatch` is `true`.fixReview the documentation on `disposalType` and `transparentIndex`. If `buildPatch` is `true`, be aware of its assumptions. For precise rendering, process `pixels` and `colorTable` manually, handling transparency and disposal based on GIF specification, or consult the library's demo for a robust rendering example.
Warnings
- gotcha The library expects GIF data as a `Uint8Array` or `ArrayBuffer`. Passing other formats (e.g., base64 strings, Blobs directly) will result in parsing errors.
- gotcha When `decompressFrames` is called with `buildPatch: true`, it generates `Uint8ClampedArray` patches. This process makes assumptions about transparency handling and disposal methods, which might not always align with complex GIF specifications or desired rendering effects, potentially leading to incorrect transparency or visual artifacts (e.g., 'white blurs').
- gotcha The `pixels` property of a decompressed frame contains color table indices, not direct RGBA color values. Developers often mistakenly try to interpret these as direct pixel colors without consulting the `colorTable`.
- gotcha Some complex or malformed GIFs may exhibit rendering issues, such as incomplete frames or visual corruption, due to subtleties in the GIF specification or specific implementation choices, particularly concerning graphic control extensions or multiple application blocks.
Install
-
npm install gifuct-js -
yarn add gifuct-js -
pnpm add gifuct-js
Imports
- parseGIF
const parseGIF = require('gifuct-js').parseGIFimport { parseGIF } from 'gifuct-js' - decompressFrames
const decompressFrames = require('gifuct-js').decompressFramesimport { decompressFrames } from 'gifuct-js' - GIF and Frame types
import type { GIF, Frame } from 'gifuct-js'
Quickstart
import { parseGIF, decompressFrames } from 'gifuct-js';
const gifURL = 'https://i.imgur.com/DrxJ5d8.gif'; // Replace with your GIF URL
async function loadAndDecompressGif(url) {
try {
const resp = await fetch(url);
if (!resp.ok) {
throw new Error(`HTTP error! status: ${resp.status}`);
}
const arrayBuffer = await resp.arrayBuffer();
const gif = parseGIF(arrayBuffer);
// Set buildPatch to true to get canvas-ready Uint8ClampedArray patches
const frames = decompressFrames(gif, true);
console.log('GIF parsed successfully. Number of frames:', frames.length);
// Example of accessing frame data
if (frames.length > 0) {
const firstFrame = frames[0];
console.log('First frame dimensions:', firstFrame.dims);
console.log('First frame delay (ms):', firstFrame.delay);
// firstFrame.patch is a Uint8ClampedArray if buildPatch was true
// firstFrame.pixels is an array of color table indices
}
return frames;
} catch (error) {
console.error('Failed to load or decompress GIF:', error);
return [];
}
}
loadAndDecompressGif(gifURL).then(frames => {
// Now you can work with the decompressed frames, e.g., draw them to a canvas
// For full rendering example, refer to the library's demo.
});