@remotion/gif
Version:
Embed GIFs in a Remotion video
60 lines (59 loc) • 2.56 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.decompressFrames = exports.decompressFrame = exports.parseGIF = void 0;
/* eslint-disable no-console */
const gif_1 = require("../js-binary-schema-parser/gif");
const parser_1 = require("../js-binary-schema-parser/parser");
const uint8_parser_1 = require("../js-binary-schema-parser/uint8-parser");
const deinterlace_1 = require("./deinterlace");
const lzw_1 = require("./lzw");
const parseGIF = (arrayBuffer) => {
const byteData = new Uint8Array(arrayBuffer);
return (0, parser_1.parse)((0, uint8_parser_1.buildStream)(byteData), gif_1.GIF);
};
exports.parseGIF = parseGIF;
const decompressFrame = (frame, gct) => {
var _a, _b, _c;
if (!frame.image) {
console.warn('gif frame does not have associated image.');
return null;
}
const { image } = frame;
// get the number of pixels
const totalPixels = image.descriptor.width * image.descriptor.height;
// do lzw decompression
let pixels = (0, lzw_1.lzw)(image.data.minCodeSize, image.data.blocks, totalPixels);
// deal with interlacing if necessary
if ((_a = image.descriptor.lct) === null || _a === void 0 ? void 0 : _a.interlaced) {
pixels = (0, deinterlace_1.deinterlace)(pixels, image.descriptor.width);
}
const resultImage = {
pixels,
dims: {
top: frame.image.descriptor.top,
left: frame.image.descriptor.left,
width: frame.image.descriptor.width,
height: frame.image.descriptor.height,
},
colorTable: ((_b = image.descriptor.lct) === null || _b === void 0 ? void 0 : _b.exists)
? image.lct
: gct,
// Same behavior as FFmpeg: If delay is 0, we set it to 100ms
// https://github.com/FFmpeg/FFmpeg/blob/060fc4e3a5acae27e5fbf2ff06419dff08a7d318/libavformat/gifdec.c#L62-L68
delay: (((_c = frame.gce) === null || _c === void 0 ? void 0 : _c.delay) || 10) * 10,
disposalType: frame.gce ? frame.gce.extras.disposal : 1,
transparentIndex: frame.gce
? frame.gce.extras.transparentColorGiven
? frame.gce.transparentColorIndex
: -1
: -1,
};
return resultImage;
};
exports.decompressFrame = decompressFrame;
const decompressFrames = (parsedGif) => {
return parsedGif.frames
.filter((f) => !('application' in f))
.map((f) => (0, exports.decompressFrame)(f, parsedGif.gct));
};
exports.decompressFrames = decompressFrames;