canvas-record
Version:
Record a video in the browser or directly on the File System from a canvas region (2D/WebGL/WebGPU) as MP4, WebM, MKV, MOV, GIF, PNG/JPG Sequence using WebCodecs and wasm when available.
93 lines (76 loc) • 2.36 kB
JavaScript
import { GIFEncoder as GIFEnc, quantize, applyPalette } from "gifenc";
import Encoder from "./Encoder.js";
/**
* @typedef {object} GIFEncoderOptions
* @property {number} [maxColors=256]
* @property {GIFEncoderQuantizeOptions} [quantizeOptions]
* @property {GIFEncoderEncoderOptions} [encoderOptions={}]
*/
/**
* @typedef {object} GIFEncoderQuantizeOptions
* @property {"rgb565" | "rgb444" | "rgba4444"} [format="rgb565"]
* @property {boolean | number} [oneBitAlpha=false]
* @property {boolean} [clearAlpha=true]
* @property {number} [clearAlphaThreshold=0]
* @property {number} [clearAlphaColor=0x00]
* @see [QuantizeOptions]{@link https://github.com/mattdesl/gifenc#palette--quantizergba-maxcolors-options--}
*/
/**
* @typedef {object} GIFEncoderEncoderOptions
* @property {number[][]} [palette]
* @property {boolean} [first=false]
* @property {boolean} [transparent=0]
* @property {number} [transparentIndex=0]
* @property {number} [delay=0]
* @property {number} [repeat=0]
* @property {number} [dispose=-1]
* @see [WriteFrameOpts]{@link https://github.com/mattdesl/gifenc#gifwriteframeindex-width-height-opts--}
*/
class GIFEncoder extends Encoder {
static supportedExtensions = ["gif"];
static defaultOptions = {
extension: GIFEncoder.supportedExtensions[0],
frameMethod: "imageData",
maxColors: 256,
quantizeOptions: {
format: "rgb565", // rgb444 or rgba4444
oneBitAlpha: false,
clearAlpha: true,
clearAlphaThreshold: 0,
clearAlphaColor: 0x00,
},
};
/**
* @param {GIFEncoderOptions} [options]
*/
constructor(options) {
super({ ...GIFEncoder.defaultOptions, ...options });
}
async init(options) {
super.init(options);
this.encoder = GIFEnc();
}
async start() {
await super.start();
this.step();
}
encode(frame) {
const palette = quantize(frame, this.maxColors, this.quantizeOptions);
const index = applyPalette(frame, palette, this.quantizeOptions.format);
this.encoder.writeFrame(index, this.width, this.height, {
palette,
delay: (1 / this.frameRate) * 1000,
...this.encoderOptions,
});
}
stop() {
this.encoder.finish();
const data = this.encoder.bytes();
this.encoder.reset();
return data;
}
dispose() {
this.encoder = null;
}
}
export default GIFEncoder;