6

I am writing open-source Falloutish 2 game in PHP+HTML+CSS+JavaScript. Right now dealing with the engine. I have this gif: https://dl.dropboxusercontent.com/u/4258402/nmwarrgb_e.gif

...which I want to convert to Data URI. I need to do this because browsers cache images and this one is not looped, so in order to be able to "run it again" when animation ends and unit goes to another tile, I need to convert it to data URI. Otherwise I'd be forced to re-download image over and over again e.g. by adding random string to the end of image file. Which works fine, but takes way too much transfer and causes lag.

This is the code I tried to use:

    var image = new Image();

    (..)

    this.convertImageObjectToDataURI = function (image) {
                var canvasTemp = document.createElement('canvas');
                canvasTemp.width = image.naturalWidth; // or 'width' if you want a special/scaled size
                canvasTemp.height = image.naturalHeight; // or 'height' if you want a special/scaled size

                canvasTemp.getContext('2d').drawImage(image, 0, 0);

                var dataUri = canvasTemp.toDataURL('image/gif');

                // Modify Data URI beginning
                dataUri = "data:image/gif;" + dataUri.substring(15);
                console.log(dataUri);

                // Return image as Data URI
                return dataUri;
};

Unfortunately it produces Data URI only for the first frame. I've tried searching plugins, reading about html canvas, but still I just don't know how to convert animated gif to data URI. Any help would be very, very mich welcomed!

Rav
  • 1,460
  • 1
  • 21
  • 33
  • The animated gif is an animation in the canvas? I think that don't animate. That's your problem. Do you need to convert it dinamically? I said, if you want to put the base64 code into a variable without upload the images to your server, you can encode it with an online tool and you don't need to encode while the game is running. – Marcos Pérez Gude Nov 28 '15 at 18:19
  • The problem is that there're about 20 000 gif animations :- ) And the concern for me is to force this gif to be started all over again, after it finishes playing for the first time. Ah, I will probably need to stick with multiple requests with random string attached to the end of it to trick the browser. – Rav Nov 28 '15 at 18:57
  • 1
    OMG, then my answer about sprites is descarted I guess. But you must know that sprites are the most used technique to the animations in games. Good luck ! – Marcos Pérez Gude Nov 28 '15 at 19:09
  • 2
    Hope your project went well! FWIW, the [data-URL format](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) is extremely simple; Just [base64-encode](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/btoa) the original gif image, and tack on `"data:image/gif;base64,"` to the beginning. – jpaugh May 18 '20 at 15:09

2 Answers2

2

It's not possible with javascript to read server files by this mode with compatibility all browsers, but I recommend you to use sprites instead of animated gifs. A sprite is a png file (that allows alpha channel) with all frames drawn separated. Imagine that file:

Dots sprite

As you can see, it's a 600x150 image (150x150 each frame, 4 frames). So you can animate with CSS animations like this:

.dots {
    width: 150px;
    height: 150px;
    background-image: url(https://i.stack.imgur.com/bCHFq.png);
    
    -webkit-animation: play .4s steps(4) infinite;
       -moz-animation: play .4s steps(4) infinite;
        -ms-animation: play .4s steps(4) infinite;
         -o-animation: play .4s steps(4) infinite;
            animation: play .4s steps(4) infinite;
}

@-webkit-keyframes play {
   from { background-position:    0px; }
     to { background-position: -600px; }
}

@-moz-keyframes play {
   from { background-position:    0px; }
     to { background-position: -600px; }
}

@-ms-keyframes play {
   from { background-position:    0px; }
     to { background-position: -600px; }
}

@-o-keyframes play {
   from { background-position:    0px; }
     to { background-position: -600px; }
}

@keyframes play {
   from { background-position:    0px; }
     to { background-position: -600px; }
}
<div class="dots"></div>

With that, you can adjust the keyframes, the velocity, the number of frames (steps), and the most important: you don't overload CPU and RAM memory in the browser client.

Good luck.

Marcos Pérez Gude
  • 21,869
  • 4
  • 38
  • 69
1

I believe there is no direct way to do that using JavaScript. Using a canvas, you'd have to draw each individual frame onto it and encode them into a GIF file. This appears to be impossible using the current API as there is no way to extract single frames (except by manually parsing the GIF file).

You might succeed by downloading the binary GIF file using JavaScript (remember cross-domain restrictions of HTTP requests) and generate a base64-encoded data URL. For example, you could use this example to get an Uint8Array which you can then convert to a base64 string.

You should probably consider generating the data URLs statically, not using JavaScript. For example, you can use this shell command to generate the data URL for your gif file:

echo "data:image/gif;base64,"`curl --silent 'https://dl.dropboxusercontent.com/u/4258402/nmwarrgb_e.gif' | base64 --wrap=0`

There is also a number of online services which will generate data URLs from files.

Community
  • 1
  • 1
Tobias
  • 7,723
  • 1
  • 27
  • 44