PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Sunday, July 17, 2022

[FIXED] How to fix .gif with corrupted alpha channel (stuck pixels) collected with Graphicsmagick?

 July 17, 2022     encode, ffmpeg, gif, graphics, graphicsmagick     No comments   

Issue

I want to convert an .avi with alpha channel into a .gif.
Firstly, I use

ffmpeg -i source.avi -vf scale=720:-1:flags=lanczos,fps=10 frames/ffout%03d.png

to convert .avi to sequence of .png's with aplha channel.
Then, I use

gm convert -loop 0 frames/ffout*.png output.gif

to collect a .gif.
But it seems that pixels of the output.gif just get stuck when something opaque is rendered on top of the transparent areas.

Here's an example:

img

As you can see the hearts and explosions do not get derendered.

P.S. FFMPEG output (collection on .png's) is fine.


Solution

I do not use Graphicsmagick but your GIF has image disposal mode 0 (no animation). You should use disposal mode 2 (clear with background) or 3 (restore previous image) both works for your GIF. The disposal is present in gfx extension of each frame in the Packed value.

So if you can try to configure encoder to use disposal = 2 or 3 or write script that direct stream copy your GIF and change the Packed value of gfx extension chunk frame by frame. Similar to this:

  • GIF Image getting distorted on interlacing

If you need help with the script then take a look at:

  • How to find where does Image Block start in GIF images?
  • Decode data bytes of GIF87a raster data stream

When I tried this (C++ script) on your GIF using disposal 2 I got this result:

disposal=2

The disposal is changed in C++ like this:

struct __gfxext
    {
    BYTE Introducer;        /* Extension Introducer (always 21h) */
    BYTE Label;             /* Graphic Control Label (always F9h) */
    BYTE BlockSize;         /* Size of remaining fields (always 04h) */
    BYTE Packed;            /* Method of graphics disposal to use */
    WORD DelayTime;         /* Hundredths of seconds to wait    */
    BYTE ColorIndex;        /* Transparent Color Index */
    BYTE Terminator;        /* Block Terminator (always 0) */
    __gfxext(){}; __gfxext(__gfxext& a){ *this=a; }; ~__gfxext(){}; __gfxext* operator = (const __gfxext *a) { *this=*a; return this; }; /*__gfxext* operator = (const __gfxext &a) { ...copy... return this; };*/
    };

__gfxext p;
p.Packed&=255-(7<<2);   // clear old disposal and leave the rest as is
p.Packed|=     2<<2;    // set new disposal=2 (the first 2 is disposal , the <<2 just shifts it to the correct position in Packed)

It is a good idea to leave other bits of Packed as are because no one knows what could be encoded in there in time ...



Answered By - Spektre
Answer Checked By - Senaida (PHPFixing Volunteer)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing