Cannot make transparent background when saving canvas to gif

Viewed 29

I'm using the very handy javascript canvas to gif script from here: https://github.com/antimatter15/jsgif

But I can't seem to get transparent backgrounds to work. It just comes out black.

HTML:

<canvas id="canvas" width="960" height="540" />

Javascript:

const canvas = document.getElementById("canvas"); // get canvas
const context = canvas.getContext('2d') //get context


ctx.fillStyle = "#000000"; // set bg color to black
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height) // fill the background


var encoder =  new window.GIFEncoder()
encoder.setRepeat(0);

encoder.setQuality(200)
encoder.setTransparent(0x000000) // set black to be transparent
        
encoder.start();
       
encoder.setDelay(delay);
encoder.addFrame(ctx);

encoder.finish();
encoder.download("download.gif");

But the result is just a gif with black background rather than transparent. What am I doing wrong?

Thanks!

1 Answers

After digging through the sourcecode of GIFEncoder.js I realized, it's not your fault - there's simply a little bug.

As soon as you determine a transparent color using the GIFEncoder's .setTransparent() method, it internally invokes the function findClosest, which searches through the actual colour palette and tries to find a near match between the stored colors and the transparent color you would like to have.

If a match is found it looks up another table - usedEntry - to find out if the color is actually used in your image - and there's the culprit. To get the index into the table it does:

var index = i / 3;

The outer loop though does not get incremented in multiples of 3, so the result of this division is always a floating point number thus there is no valid index.

If you replace the above with:

var index = (i + 1) / 3;

it will work.

Edit

Obviously this ain't the only bug with the GIFEncoder library. GIF files can have a shared global color palette and optionally local color palettes for subsequent frames - which this library takes use of. To do this it analyzes the pixel data for each frame and writes the used color indexes - like above - into the usedEntry array. Unfortunately it does not get reset for a new analysis stage.

If you add

usedEntry = [];

at the begining of the analyzePixels() function it will keep the transparency for animations.

Related