Animated gif only loops once in Chrome and Firefox

痞子三分冷 提交于 2019-11-27 07:17:02
Spektre

I was facing the same problem with my GIF encoder/decoder class I wrote some time ago (and improving with time to time). I found out the solution for this just yesterday. The GIF is completely fine the problem is on modern internet browser's side. Infected browsers are Opera,IE,Chrome (didn't test others).

After some investigation on the matter (by comparing looping and non looping images) I found out that these browsers GIF decoders are ignoring the looping parameters in GIF file. Instead they are depending on undocumented application extension in the first frame of GIF file.

So the solution is to add this extension command just before first frame image data. Add this chunk:

0x21,0xFF,0x0B,"NETSCAPE","2.0",0x03,0x01,0x00,0x00,0x00

This will force browsers to loop endlessly.

Here example:

Hex view so you see how it is added:

The GIF is not sensitive on inserting/reordering non image chunks of data so you can insert this before first image on any place between any other extension. I put it directly after header + palette. Which can be done with C++ or any other language. (no re-encoding is needed). For more info see:


[Edit by Reed Dunkle]

You can also do it manually with a Hex Editor. I used "Hex Fiend" on macOS Sierra.

Search for 21 F9 in the beginning portions of hex (this is the header). In the photo above, it is 21 F9 04 04 00 00 00 00. Yours could be slightly different, but notice it comes before 2C, which marks the beginning of an image block.

Before the 21 F9... portion, insert the following hex, marked as the "application extension" in the photo above:

21 FF 0B 4E 45 54 53 43 41 50 45 32 2E 30 03 01 00 00 00

Save, and test it.

Addon by Spektre: Beware 21 F9 marks gfx extension chunk which is optional so It may not be present for all or any frames (but that is really rare these days)

You can use the gifsicle command line tool to process an animated gif and add in the correct looping that is compatible with all browsers:

Animation options: -l, --loopcount[=N] Set loop extension to N (default forever).

so in Terminal I do:

$ gifsicle --loopcount problem.gif > fixed.gif

Which produces a new Animated GIF that works in Chrome & Firefox as well as Safari.

You can either state a finite number of loops, or you can make the movie loop forever. INFINITE (or -1) loops the movie over and over as long as the page is on the screen. For example, this code produces a movie which loops continuously:

<img 
  src="../graphics/moonflag.mpg" 
  dynsrc="../graphics/moonflag.mpg"
  loop=infinite
  alt="Astronauts on the moon">

Source

Wrote PHP gif fixer based on answer by Spektre:

/**
 * gif image loop fixer, prints image full url
 * 
 * as this is written as a part of framework, there are some config options
 */

// put your images absolute path here eg '/var/www/html/www.example.com/images/'
// or use autodetection below
$GLOBALS['config']['upload_path'] = str_replace("\\", "/", trim(getcwd(), " /\\")).'/images/';

// put your images relative/absolute url here, eg 'http://www.example.com/images/';
$GLOBALS['config']['upload_url'] = '/images/';

function _ig($image){

    $image_a = pathinfo($image);

    $new_filename = $GLOBALS['config']['upload_path'].$image_a['dirname'].'/_'.$image_a['filename'].'.'.$image_a['extension'];
    $new_url = $GLOBALS['config']['upload_url'].$image_a['dirname'].'/_'.$image_a['filename'].'.'.$image_a['extension'];

    if ($image_a['extension'] == 'gif'){

        if (!file_exists($new_filename)){

            // load file contents
            $data = file_get_contents($GLOBALS['config']['upload_path'].$image);

            if (!strstr($data, 'NETSCAPE2.0')){

                // gif colours byte
                $colours_byte = $data[10];

                // extract binary string
                $bin = decbin(ord($colours_byte));
                $bin = str_pad($bin, 8, 0, STR_PAD_LEFT);

                // calculate colour table length
                if ($bin[0] == 0){
                    $colours_length = 0;
                } else {
                    $colours_length = 3 * pow(2, (bindec(substr($bin, 1, 3)) + 1)); 
                }

                // put netscape string after 13 + colours table length
                $start = substr($data, 0, 13 + $colours_length);
                $end = substr($data, 13 + $colours_length);

                file_put_contents($new_filename, $start . chr(0x21) . chr(0xFF) . chr(0x0B) . 'NETSCAPE2.0' . chr(0x03) . chr(0x01) . chr(0x00) . chr(0x00) . chr(0x00) . $end);

            } else {

                file_put_contents($new_filename, $data);

            }

        }

        print($new_url);

    } else {

        print($GLOBALS['config']['upload_url'].$image);

    }

}

This makes copy of the image.gif as _image.gif with needed string inserted after colours table and prints out new src url. (Checks if the image is already fixed first.)

Usage:

<img src="<?php _ig($image); ?>">

or

<img src="<?php _ig('image.gif'); ?>">

Disclaimer: no responsibilities taken and I know that this can be optimised :)

With ImageMagick, often pre-installed:

convert -loop 0 bad.gif good.gif

It seems that Gimp will allow you to export a gif that will loop properly. Just open the gif, then 'File' > 'Export As' and check the "As Animation" and "Loop Forever" checkboxes. I don't know if this updates the file as in Spektre's answer, but my test image looped correctly in FireFox 60.0b8 (64-bit), Chrome Version 65.0.3325.181 (Official Build) (64-bit), and Safari Version 9.1.1 (11601.6.17).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!