jnordberg / gif.js

JavaScript GIF encoding library
http://jnordberg.github.io/gif.js/
MIT License
4.78k stars 668 forks source link

GIF color issues #70

Closed fordhurley closed 6 years ago

fordhurley commented 7 years ago

I'm seeing some really bad color palette issues when trying to use this, possibly because I'm trying to push it too far. Here's what I'm seeing:

gif js

Generated with this code:

var numFrames = 50;
var width = 300;
var height = 300;

var canvas = document.querySelector("canvas");
canvas.width = width;
canvas.height = height;

var gif = new GIF({
  workers: 4,
  workerScript: "gif.worker.js",
});

gif.on("finished", function(blob) {
  var img = document.querySelector("img");
  img.src = URL.createObjectURL(blob);
});

var ctx = canvas.getContext("2d");
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.font = "bold 30px Helvetica";

var i = 0;
function renderFrame() {
  var p = (i + 1) / numFrames;

  var grad = ctx.createLinearGradient(0, 0, 0, p*height);
  grad.addColorStop(0, "#d4e5f6");
  grad.addColorStop(1, "#5183c8");
  ctx.fillStyle = grad;
  ctx.fillRect(0, 0, width, height);

  ctx.fillStyle = "black"
  ctx.fillText("😀", width/2, height/2);

  gif.addFrame(canvas, {
    copy: true,
    delay: 200,
  });

  i++;
  if (i < numFrames) {
    setTimeout(renderFrame, 0);
  } else {
    gif.render();
  }
}
renderFrame();

Link to codepen.

Now, I know that gifs aren't going to encode gradients well, due to the limited color depth. My problem is that the emoji in the center is so unstable, changing drastically from frame to frame. In fact, if I remove the gradient and just use a moving 2 color background, I still see issues with the emoji, although not as bad:

gif js_nograd

Codepen for this gif.

Am I trying to push gif.js too far, or is this the result of a bug?

jnordberg commented 7 years ago

You've hit a limitation of the color quantization algorithm, what you can do is increase the sample frequency to make it more accurate, options.quality or use the (undocumented because buggy) globalPalette option