antimatter15 / jsgif

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

setTransparent #3

Open forresto opened 12 years ago

forresto commented 12 years ago

Have you gotten setTransparent(Number color) to work?

forresto commented 12 years ago

Like... what kind of number is it expecting for the color? I'm passing 0xFFFFFF but white isn't transparent... sometimes a random other color is but I can't figure it out.

forresto commented 12 years ago

Anybody want to hack on https://wiki.mozilla.org/APNG_Specification encoding with me?

forresto commented 12 years ago

Here is one of the rare frames where transparency (0x00FF00) worked:

transparency worked

Most of the time it doesn't:

transparency didn't work

forresto commented 12 years ago

This might be a bug: GIFEncoder.js#L351

        for (var i/*int*/ = 0; i < len;) {
          var dr/*int*/ = r - (colorTab[i++] & 0xff);
          var dg/*int*/ = g - (colorTab[i++] & 0xff);
          var db/*int*/ = b - (colorTab[i] & 0xff);
          var d/*int*/ = dr * dr + dg * dg + db * db;
          var index/*int*/ = i / 3;
          if (usedEntry[index] && (d < dmin)) {
            dmin = d;
            minpos = index;
          }
          i++;
        }

That var index/*int*/ = i / 3; will be 2/3 the first time. I changed the block to:

        for (var i/*int*/ = 0; i < len;) {
          var dr/*int*/ = r - (colorTab[i++] & 0xff);
          var dg/*int*/ = g - (colorTab[i++] & 0xff);
          var db/*int*/ = b - (colorTab[i++] & 0xff);
          var d/*int*/ = dr * dr + dg * dg + db * db;
          var index/*int*/ = (i / 3) - 1;
          if (usedEntry[index] && (d < dmin)) {
            dmin = d;
            minpos = index;
          }
        }

With this I'm getting better, but still random results:

better, but still random results

forresto commented 11 years ago

Testing it today... colors were crap at 200x200 and fine at 300x300... maybe has something to do with this. Will look more.

g-regor commented 11 years ago

The quantization algorithm puts multiple entries into the color table for the same color, so then there are different indices for the same color. Because of that, color that should be transparent, has different index than the transparency index.

I wrote a fix, that sets all the pixel indices, that should be transparent to transparency index. GIFEncoder.js#L337

if (transparent != null) {
    transIndex = findClosest(transparent);

    var r = colorTab[transIndex*3];
    var g = colorTab[transIndex*3+1];
    var b = colorTab[transIndex*3+2];
    var trans_indices = [];
    for (var i=0; i<colorTab.length; i+=3)
    {
        var index = i / 3;
        if (!usedEntry[index]) continue;
        if (colorTab[i] == r && colorTab[i+1] == g && colorTab[i+2] == b)
            trans_indices.push(index);
    }
    for (var i=0; i<indexedPixels.length; i++)
        if (trans_indices.indexOf(indexedPixels[i]) >= 0)
            indexedPixels[i] = transIndex;
}
Pl4n3 commented 11 years ago

Also, to run, line 363 must use floor function here:

var index/int/ = Math.floor(i / 3);

forresto commented 11 years ago

Thanks @grego87, transparent works now:

trans

There is still a huge difference in the color quality at 200x200 vs 300x300... any leads on that bug? 200x200 vs 300x300 (here is the meemoo app that I used to make this test)

antimatter15 commented 11 years ago

Have you tried out https://github.com/deanm/omggif

forresto commented 11 years ago

It does look a little cleaner but you have to manually set the palette... I might port that part of yours to work with his...

raducostea commented 11 years ago

Hi,

Any idea when the quality depending on the canvas size may get fixed?

forresto commented 11 years ago

I'm pretty sure the size/color bug #6 is in NeuQuant.js, because I got it working with OMGGIF and they bug is still there. I'm going to start a bounty on Stack Overflow.

forresto commented 11 years ago

@raducostea This patch should fix the color/size issue: https://github.com/antimatter15/jsgif/pull/8/files

memalign commented 2 years ago

Note that there are TWO places that need to be changed from: var index = i / 3; To var index = Math.floor(i / 3);

Without these two fixes the wrong color is chosen as the transparency color.

(I discovered this when debugging why 0x000000 worked as a transparency color but 0xFFFFFF did not)

flyskywhy commented 1 year ago

You can try gifenc

Because my react-native-gifencoder is also some fork of gif.js

But in my react-native-runescape-text I replace react-native-gifencoder with gifenc for Fix when one color e.g. '#ff0000' only have 1 or 2 or 3 pixel in one frame, the generated gif pixel will be '#9f0000'; fix some frame not transparent but black; reduce gif size 10x