The Tiniest GIF Ever

Yesterday I was base64-encoding an image so I could send it to CouchDB to test some code I’m working on for a client. It reminded me of something I did a while back to set cookies on a remote server.

Basically, a small PHP script was put on the remote server which took a couple of GET parameters and set some cookies based on their values. The script then output a 1×1 transparent GIF. A PHP script on the local server generated an IMG tag which linked to this image and set the parameters based on the COOKIES on the local server.

This process also had to happen in the reverse direction, so I had to send the script to developers on the other side. I wanted to keep it as simple as possible, so I put the actual image contents in the PHP file as a base64 encoded string. I used the GIMP to generate the smallest transparent GIF I could manage so there wouldn’t be too huge of a nasty string in the file. I came up with something like the following:

<?php
setcookie('foo', $_GET['foo']);
header('Content-Type: image/gif');
echo base64_decode('R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==');
?>

Remembering this got me to wondering, how small could you make a GIF? The file generated by the GIMP was only 43 bytes, but it seemed to be that you should be able to make a file which is representing a single pixel a bit smaller than that.

So, with equal parts of determination and derangement, I set about finding out.

Though of somewhat dubious usefulness, I managed to generate a perfectly valid GIF of only 26 bytes in length, which has the potential to display completely differently in various different software.

Read on to see how I found my way to this point.

Starting point: the GIF89a specification

The file generated by the GIMP, as I said, was 43 bytes long. You can find it here: tinytrans.gif

To understand what was taking up all those bytes, I read through the GIF89a Spec. The file tinytrans.gif above consists of the following sections:

  • Header, 6 bytes: Consists of the bytes “GIF” and the version number, which is usually “89a”.

  • Logical Screen Descriptor, 7 bytes: Without going into too much detail, this section of the file indicates the following:

    • The file is 1×1 pixels in size
    • There is a global color table
    • There are 2 colors in the global color table, the second one should be used as the background color
  • Global Color Table, 6 bytes: Consists of 3 bytes per color, a byte for red, green, and blue, respectively. In our file, the first color is white an the second color is black.

  • Graphic Control Extension, 8 bytes: Used to indicate that the second color in the color table should be treated as transparent (can also be used for animation parameters, but isn’t in this file)

  • Image Descriptor, 10 bytes: A GIF file can actually contain multiple “images” within it, which keeps you from having to specify image data for parts of the image which have the same color as the background color. Each image block has a position and size within the overall image size. In the above file, the position is 0,0 and the size is 1×1.

  • Image Data, 5 bytes: One LZW-encoded block of image data. It takes 5 bytes to represent the single pixel the image has in it. The compression algorithm wasn’t designed to compress a single byte very well.

  • GIF Trailer, 1 byte: A single byte with a hex value of 3B (“;” in ASCII) indicates the end of the GIF.

Making a smaller GIF

Based on the required structures for a transparent GIF, it turns out that 43 bytes is pretty close to as small as you can get.

But, I managed to figure out one trick to make it a bit smaller. It’s mentioned in the standard that it is optional to have a global color table. Of course, it’s undefined as to what happens when you make a GIF without a color table at all (there are also optional local color tables per image block).

When you have a color table index defined as transparent, however, GIF decoders don’t seem to care that there isn’t actually a color table.

So I changed the logical screen descriptor to indicate there was no global color table and removed the table itself, saving a total of six bytes, bringing the file size down to a mere 37 bytes.

Here it is in all its glory: handtinytrans.gif

Interestingly enough, Wordpress gave me a lovely list of error messages of GD complaining that this isn’t a valid GIF file, despite the fact that Firefox and the GIMP both open and display (is it “displayed” when it’s transparent?) the file just fine.

So there you go, the tiniest transparent GIF possible (if you can make one smaller, let me know).

But of course, there’s room still for the tiniest GIF ever.

Even smaller, no longer transparent

To make it even smaller, I looked to the biggest remaining “optional” block in the image, the graphic control extension. If you don’t need transparency, this block is no longer needed, and that’s another 8 bytes you can take away.

Sadly, I wanted a whilte image, and I couldn’t get it to come out white without adding the global color table back in, so I only managed to trim 2 bytes off of the file.

Still, 35 bytes is indeed smaller: handtinywhite.gif

The tiniest possible GIF

If I remove the constraint of having the image be white (or any color I choose), I can make it even smaller, though admittedly this becomes much less useful.

I removed both the global image table and the graphic control extension, and then no matter what color the pixel originally was, it comes out black. From there, I took it a step further, because the standard never says you have to actually set any pixels in the image, I removed the LZW encoded image data. I left the required lzw code-size header and block terminator, because without those Firefox and the GIMP both complained it wasn’t a valid GIF, and then I had it.

The tiniest GIF ever, 26 bytes: handtinyblack.gif

Despite the fact that this is called “handtinyblack.gif”, black is just the color that the GIMP chooses to display when there’s no global color table. It’s stated in the spec “If no color table is available at all, the decoder is free to use a system color table or a table of its own.”

This means that any GIF decoder is free to pick whatever color it wants for this image. Opening this image in Firefox at various different times, it has show up as shades of blue, green and brown, as well as transparent if set as a background image.

Tags: , ,

12 Responses to “The Tiniest GIF Ever”

  1. Webdev, pe stomacul gol … » Blog Archive » The Tiniest GIF Ever Says:

    [...] Bonser a scris un articol interesant despre cum se poate genera un GIF valid de maxim 26 [...]

  2. alecu Says:

    I enjoyed reading your article. Nice hack.

  3. Brent Says:

    Interesting :)

  4. kL Says:

    Ooo, if browser gives different color each time, it means uninitialized memory, which means stealing potentially sensitive data 768 bytes at a time! (with canvas).

  5. pib Says:

    @kL, well, if they’re following the standard, it’s actually pulling the palette from other images that have been loaded in the browser. That’s a suggestion that the standard has in it, though, so who knows where it’s coming from.

    Here’s an image I converted to GIF and then removed the color table from:

    It seems to just show up black for me.

    Ten points to the first person to find the picture hidden within :P

  6. Scott Says:

    pretty cool read… here is your image :

  7. Scott Says:

    how about just a link: http://xmiles.info/yeah.png

  8. Gerry Says:

    Amazingly, if you use your code and vary bytes 7,8,9,10, you can create a 26 byte image of any size (theoretically up to 65,535 pixels by 65,535 pixels). See http://seconds.com/tiny.gif

  9. pib Says:

    Gerry: Oh, I hadn’t even thought about that. Yeah, I didn’t put any image data, so you can define whatever size you want…I’m not sure I can think of much use of such a huge one-color image, but it’s good to know I can do it in just 26 bytes if I want. :)

  10. Gerry Says:

    I put up another test at seconds.com/pixel.php?x=16&y=255 How would I add color/transparency? Code is: $x=1;$y=1; if($_GET['x']) $x=$_GET['x']; if($_GET['y']) $y=$_GET['y']; Header( “Content-type: image/gif”); printf(“%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c”,71,73,70,56,57,97,$x,0,$y,0,0,255,0,44,0,0,0,0,1,0,1,0,0,2,0,59); //Didn’t use extra byte for x/y ?> How hard would it be to create textured background images of any size/color and stay within 1kB packet size? Seems crazy to have to use all the %c%c%c’s :-(

  11. weGIF Says:

    i am wandering what this smallest or tiniest GIF ever looks like… well i guess this is one of the innovations on GIF technology… this is really interesting and must be featured on http://www.wegif.com/ Gif Photo Animation

  12. steve Says:

    Pretty interesting, never thought that…hey! what happened to that “Cancer Cure” you were working on??? >->O

Leave a Reply