paazmaya.fi

The Website of Juga Paazmaya | Stories about Web Development, Japanese Martial Arts, Hardware prototyping and travelling

Base64 Encoding

A rather interesting way to reduce HTTP requests made by clients while loading a web page is to include binary data directly to CSS or HTML markup.

For example the CSS property background-image or img element via src property can take Base64 encoded string. This adds the possibility to include some of the smaller images directly in the style sheet or other markup. Naginata Finland - Logo

Before Base64 encoding, it might be possible to reduce the image size. For PNG files, pngcrunch takes an extra effort to remove unnecessary data and compress the given PNG image. It is a command line tool and one simple solution would be:

pngcrush.exe -brute logo.png logo_reduced.png

The given example image from naginata.fi/img/logo.png was originally 9642 bytes once exported of SVG image in Inkscape and after crunching became 6300 bytes.

Once encoded to Base64, the resulted string takes up to 8532 bytes. If the split to chunks is left out, thus the Base64 string is a one liner, it takes 8400 bytes. In case the latter version would be compressed with Gzip by using maximum compression level, the size is reduced to 6373 bytes.

The code below can be used to go through all images in “img” directory and output a comparison of the resulting sizes:

header('Content-type: text/plain');

$images = glob('img/*.png');

foreach($images as $img)
{
    echo $img . "\n";

    // Original
    $data = file_get_contents($img);
    $gzip = gzcompress($data, 9);
    echo 'Original: ' . strlen($data) .
        ', compressed: ' . strlen($gzip) . "\n";

    // One line Base64
    $base64 = base64_encode($data);
    $gzip64 = gzcompress($base64, 9);
    echo 'Base64 oneline: ' . strlen($base64) .
        ', compressed: ' . strlen($gzip64) . "\n";

    // Multiline Base64
    $base64n = chunk_split(base64_encode($data), 64, "\n");
    $gzip64n = gzcompress($base64n, 9);
    echo 'Base64 multiline: ' . strlen($base64n) .
        ', compressed: ' . strlen($gzip64n) . "\n";

    echo "\n";
}

The code could produce something similar to the following output, this was done for naginata.fi:

img/controls.png
Original: 570, compressed: 581
Base64 oneline: 760, compressed: 600
Base64 multiline: 772, compressed: 615

img/favicon.png
Original: 835, compressed: 846
Base64 oneline: 1116, compressed: 871
Base64 multiline: 1134, compressed: 889

img/link-arrow.png
Original: 165, compressed: 160
Base64 oneline: 220, compressed: 185
Base64 multiline: 224, compressed: 190

img/logo-green-57x57.png
Original: 4139, compressed: 4150
Base64 oneline: 5520, compressed: 4195
Base64 multiline: 5607, compressed: 4281

img/logo-red-57x57.png
Original: 3924, compressed: 3935
Base64 oneline: 5232, compressed: 3973
Base64 multiline: 5314, compressed: 4054

img/logo.png
Original: 6300, compressed: 6311
Base64 oneline: 8400, compressed: 6373
Base64 multiline: 8532, compressed: 6499

img/mobile-logo.png
Original: 2791, compressed: 2802
Base64 oneline: 3724, compressed: 2840
Base64 multiline: 3783, compressed: 2897

img/openid-icon-100x100.png
Original: 1377, compressed: 1388
Base64 oneline: 1836, compressed: 1399
Base64 multiline: 1865, compressed: 1429

After the encoding is done, the image could be shown as such:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEU..." />

Rather simple to add in any existing dynamic markup creation.