An optimization technic for image optimization freaks.

This morning, you need to add to some website an image that contains both a photography and text. Pretty easy to do with your favorite image editor.


Just created image

You save it as a JPEG and you see the weight on your drive: 511KB!

So it’s time to optimize it, and here comes the hard part… If you optimize the image as a JPEG below the 80% quality, you’re able to obtain a small weight, but the quality of the text suffers, with some approximations and artefacts due to the compression algorithm. It’s too sad, because your background photography is still good with a 65% compression…

JPEG encoding artefacts

You try as a PNG: the quality is perfect, but it’s even bigger than the original JPEG! So you end up trying to balance JPEG encoding and text quality and finally choose a quality of 90%.

JPEG 100%: 511KB
PNG: 587KB
JPEG 90%: 84KB

Well, there might be a solution for this problem …

Keep the background and the text in two separated images…

Save the background in JPEG and optimize it as much as you want.

optimized background

Save the text as a PNG with a transparent background and optimize it losslessly (ImageOptim on Mac or online).

optimized text

… and use SVG to stick them into a single image file

You will argue, you could insert these two images in HTML and position them on top of each other. Yes, definitely! Even better, write the text in HTML directly if you can!

But what if you REALLY need a single image file, like if it needs to be inserted in your Wordpress, in a carousel, in any template that does not allow anything but an image? Or maybe you simply want to keep the semantics of a single real image in your markup.

A little known SVG functionnality lets you insert a non-SVG image inside an SVG, base64 encoded. Use your text editor and create an SVG file like this:

<svg width="800" height="600">
    <image x="0" y="0" width="800" height="600" xlink:href="data:image/jpg;base64," />
    <image x="0" y="0" width="800" height="600" xlink:href="data:image/png;base64," />

Then compare with JPEG encoding test files. The result file is not always smaller than JPEG. It will depend on the optimization capacity of both JPEG and PNG files separately.

But wait! Compare the weights after compressing your SVG (with gzip or zip). Unlike the other image formats, SVG is an uncompressed format.

Make sure your server correctly serves your SVG files gzipped. That’s a very common configuration mistake. Gzip is what will prevent base64 encoding to make performance implications.

check gzip compression


(See browser compatibility below if your browser doesn’t display the image)

result svg file

JPEG background 65% alone: 32KB
PNG text alone: 17KB
Result SVG: 64KB
Result SVG gzipped: 47KB

As you can see, base64 encoding is not a problem: the gzipped SVG is even smaller than the sum of the JPEG and the PNG.

The text could also be directly written with SVG. Of course, in this case, don’t base64 encode it.

Browser compatibility

Be careful! Safari 8 is not able to display base64 encoded images inside an SVG if the SVG is loaded via <img>. It’s working correctly with an <object> tag. It is fixed in Safari 9.

IE8 is not able to understand SVG images at all.

I started a small tool

Here is a command line tool I wrote, that will do the technical part for you: base64 encode the files and inject them into the SVG.

Special thanks to Sara Soueidan — Front-end and SVG expert — for reviewing this article.