antimatter15 / jsgif

Save a HTML5 Canvas to GIF and Animations. A port of as3gif GIFPlayer to JS
http://antimatter15.com/
MIT License
1.07k stars 138 forks source link

Global color map #35

Closed xiaozhuai closed 2 years ago

xiaozhuai commented 3 years ago

NeuQuant produce good quality color map. For local color map, it will better be for one single frame, but may cause color difference between multiple frames. Can we use a global color map here?

joswhite commented 3 years ago

Making the color map be the same for all frames is quite easy. In GIFEncoder.js, you can do:

// with variable declarations (line 61)
var nq = null;
exports.reuseColorTable = false;

// in analyzePixels (line 335)
indexedPixels = [];
if (!nq) {
    nq = new NeuQuant(pixels, len, sample); // initialize quantizer
    colorTab = nq.process(); // create reduced palette
}
// map image pixels to new or existing palette
var k = 0;
for (var j = 0; j < nPix; j++) {
    var index = nq.map(pixels[k++] & 0xff, pixels[k++] & 0xff, pixels[k++] & 0xff);
    usedEntry[index] = true;
    indexedPixels[j] = index;
}
if (!exports.reuseColorTable) {
    nq = null;
}
pixels = null;

This is what I'm doing in the application I'm writing. The only downside is that the global color map is based off of the first frame, so if the first frame is not representative of the colors in the rest of the frames, the colors in those frames will be wonky. Other than that it is quite nice because reusing the color map speeds up encoding by about 40%, and static objects no longer have the weird "glimmer" throughout the GIF from the colors changing slightly from frame-to-frame.

xiaozhuai commented 3 years ago

@joswhite Thanks for your reply! Just like your said, based off the first frame will behaves incorrectly in some cases. It can be an option, but may not be the default behavior.