37

I have an animated gif that I want to display any time a page is loading. When I view the image outside of a browser, the image loops infinitely and works just fine, but whenever I'm displaying the image in a browser, the animation only loops once. Does anyone have any suggestions for making the image loop infinitely?

Currently I'm just doing this to make the image appear which does make it appear, but only loops once:

document.getElementById('ajaxloader').innerHTML = 
    '<img src="images/ajax-loader.gif" title="Loading, please wait..">';
Ryan
  • 617
  • 2
  • 7
  • 16
  • 1
    show us your image - upload it somewhere – Zoltan Toth Jun 03 '12 at 04:05
  • @ZoltanToth Where would you like me to upload it? It is a .gif that I had generated from http://ajaxload.info/. – Ryan Jun 03 '12 at 04:10
  • 1
    It seems to work - http://jsfiddle.net/3ZWpD/1/ (I've used the same generator for the GIF) – Zoltan Toth Jun 03 '12 at 04:17
  • @ZoltanToth Thanks for your time. I ended up just getting a different loading image from a different site that generates them. Not sure what was wrong with the one I originally had, but the new one is working. – Ryan Jun 04 '12 at 01:45
  • This is not programmer related and isn't even fit for any Stack Exchange website. Instead it belong on Google's bug site. – Tyler Crompton Jul 10 '13 at 17:47
  • @Ryan added an answer I know this is old question but I finally find/solve the problem I was facing for a long time (got the feeling is the same issue but without sample image of yours is hard to tell) so if you are curious take a look. – Spektre Jun 28 '16 at 17:45
  • There are options for delay between frames and number of times to loop. I suppose it depends on how detailed your .gif creation software is. See [Optimizing animated GIFs](http://www.webreference.com/dev/gifanim/options.html "Optimizing animated GIFs") – dadinck Nov 01 '12 at 21:37
  • Can you please review answers? – Matt Sephton Jun 27 '17 at 14:13

6 Answers6

28

I was facing the same problem with my GIF encoder/decoder class I wrote some time ago (and improving from time to time). I found out the solution for this just yesterday. The GIF is completely fine the problem is on a modern internet browser's side. Affected browsers are Opera, IE, and 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 files. Instead they are depending on an 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 is an example:

looping

Hex view so you see how it is added:

hex

The GIF is not sensitive on inserting/reordering non-image chunks of data, so you can insert this before the first image in 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).

Andrew Morton
  • 24,203
  • 9
  • 60
  • 84
Spektre
  • 49,595
  • 11
  • 110
  • 380
  • 6
    "Infected browsers" xD – Vinay Nov 09 '16 at 12:55
  • 1
    This definitely works and should be accepted as the best answer. – Grim Mar 12 '17 at 05:04
  • There are much easier answers that avoid possible human error. Hex editing a file is difficult! @grimlek – Matt Sephton Jun 27 '17 at 14:11
  • @MattSephton who would do this manually? Simple script can do it easily (like Rauli Rajande did) ... all the info to do this is in the answer and the 2 links at the bottom of it also this is the only way to do this if one does not have access to the page code itself like here on SO/SE ... common workarounds are not applicable in such case – Spektre Jun 27 '17 at 14:58
  • @Spektre thanks for pointing out Rauli's script, I was had missed that it was related. I disagree that this is the only way to do it (see my answer for a more elegant solution) and also it's not possible to control the looping through markup. – Matt Sephton Jun 27 '17 at 15:44
  • @MattSephton the tool most likely does the same thing as my answer otherwise it would not work in brownsers .... just check if the NETSCAPE string is added at the start of GIF somewhere to verify .... if not then it may exploit other "undocumented feature" of used GIF or presentation framework PS correct GIF loop options are ignored in brownsers. – Spektre Jun 27 '17 at 16:12
  • Worked exactly. Thank you for the details and for the tip on the hex editor. Been a good while since I've done that. Fun. – Will England Apr 30 '20 at 12:34
27

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.

Matt Sephton
  • 3,711
  • 4
  • 35
  • 46
12

With ImageMagick, often pre-installed:

convert -loop 0 bad.gif good.gif
YvesgereY
  • 3,778
  • 1
  • 20
  • 19
2

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). gimp loop forever

origamifreak2
  • 193
  • 1
  • 1
  • 10
1

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

minimal
  • 457
  • 3
  • 15
  • http://stackoverflow.com/a/19808575/1256925 - usually lowercase is both easier to type and to read. – Joeytje50 Jan 19 '14 at 03:27
  • 3
    This is the wrong answer, the deprecated loop attribute only worked with movies, not GIFs. Looping is encoded in the GIF, not the image tag. – Andy Ray Nov 09 '16 at 22:02
1

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 :)

Rauli Rajande
  • 2,010
  • 1
  • 20
  • 24