benjaminadk / gif-encoder-2

Encode GIFs with Node
The Unlicense
58 stars 18 forks source link

Transparent color not replaced on all frames #10

Open JeffWScott opened 3 years ago

JeffWScott commented 3 years ago

I'm having an issue getting transparent to work for me.

I'm creating GIFs from canvas data. The transparent will be fine for some frames and then not for others. I'm not sure what's going on or how to solve this.

This is an example of an auto generated GIF file from some Canvas data and this is an example of the canvas data it's derived from.

As you can see there are a few frames where the transparency is replaced just fine. Then a few frames where it renders as the "bright-green" color that I'm setting as the "transparency color".

The color pallet I use is set and known, there are only 57 of them, so I know that the "bright-green" is not actually used in this art at all.

This is the code that I'm using to generate the GIF files. I would love some help here please!


    let encoder = new GIFEncoder2(canvas.width, canvas.height);

    let stream = encoder.createReadStream();

    stream.pipe(res)
    stream.pipe(fs.createWriteStream(`./GIFS/${fileName}.gif`))
    encoder.start();

    encoder.setRepeat(0);   // 0 for repeat, -1 for no-repeat
    encoder.setDelay(thingInfo.speed);  // frame delay in ms
    encoder.setQuality(1); // image quality. 10 is default.
    encoder.setThreshold(0);

    # make this color transparent
    encoder.setTransparent("0x00FF15")

    # cycle through each frame in the animation
    frames.forEach((frame, index) => {
        if (index <= frames.length){
            #clear the context of previous frame data
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            # for each frame cycle through the pixel color data and draw each one as a rectangle
            frame.forEach((letter, index) => {
               # match the "pixel letter" to the corresponding hex color
               ## If the "pixel letter" is A then set it as our transparent pixel hex 
                if (letter === "A") ctx.fillStyle = "#00ff15"

                else ctx.fillStyle = letter_to_color[letter];

                let rowBefore = Math.floor(index / numOfPixels)
                let rowAdj = (pixelSize * rowBefore)
                let y = Math.floor(index / numOfPixels)
                let x = (index - (y * numOfPixels)) * pixelSize
                ctx.fillRect(x, rowAdj, pixelSize, pixelSize);

               # Add text each frame
                if (!shareLink){
                    ctx.font = `21pt Roboto`;
                    ctx.textBaseline = 'middle';
                    ctx.textAlign = 'center';
                    ctx.strokeStyle = watermark.strokeColor;
                    ctx.lineWidth = 1;
                    ctx.miterLimit=2;
                    ctx.strokeText(config.watermark, canvas.width / 2, canvas.height - (canvas.height / 7));
                    ctx.fillStyle = watermark.fillColor;
                    ctx.fillText(config.watermark, canvas.width / 2, canvas.height - (canvas.height / 7));
                }
            })

            # add frame to the GIF
            encoder.addFrame(ctx);
        }

    })

    # Create GIF
    encoder.finish();
vdenisenko-waverley commented 3 years ago

Having same problem, is there a working solution to this?

mfauveau commented 3 years ago

I've seen the same issue. It depends on the animation. For some animations, it works fine for others only the first frame is transparent.

@benjaminadk any ideas?