Sometimes it seems that not a month goes by without another “Pure CSS Something” project. Most recently, it was the Pure CSS Twitter “Fail Whale” page that has been making the rounds on Twitter and social news sites for the last few days. Before that, we had the Opera logo made in CSS, and many, many others.

It got me wondering – could one write a program that converts any image into pure CSS & HTML?

As it turns out, that’s already been done. However, I was pretty sure it could be done better – despite limiting the maximum output resolution to 100×100, the CSS/HTML code produced by the aforementioned converter was truly humongous. Surely I could improve on that. Thus I went ahead and wrote my own image to CSS converter anyway.

The result, lovingly code-named “Pure CSS Perversion”, produces remarkably space-efficient* HTML and CSS code for a wide range of input images. You can try it out here.

*Only in the context of image-to-CSS conversion. It’s laughably inefficient when compared to most image file formats.

Examples

Descent Into Optimization

For those interested in such things, here is a detailed explanation of how the converter works, including a tedious step-by-step account of how I arrived to the current algorithm. You can also download the source code.

1. Starting Simple
The simplest way to encode an image as HTML/CSS is to convert each image pixel to a separate <div> element 1×1 pixels in size and use an inline style attribute set the div’s background color to that of the pixel. Example :

This produces good-looking results, but the amount of HTML code quickly balloons out of control. Even a modest 200×200 picture would result take up over 1 MB when encoded in this way, which is wasteful and can even crash some browsers.

2. Palletise and Cassify
The easiest way to reduce the file size of the “pure CSS” image is to convert it to a palette-based format and create a new CSS class for each palette color. This is what my first version of the image-to-CSS converter did.

As you can see, I’ve also moved the rules that apply to all DIVs to a separate CSS block.

3. Run-Length Encoding
To further reduce the code size, we can detect continuous runs of the same color and encode each of them using only a single, wider <div>. To avoid explicitly writing out the width of each element, lets generate CSS classes for widths :

5. Default Colors
We can squeeze out a few more bytes by determining the color that’s most frequently used in a given row and adding it as the background color to the container element. Then we can omit the color class from those elements that match the most common color.

6. Perversion Begins
Hmm, look at all those byte-hogging <div> elements – each eating up 3 bytes on tag name alone. Plus, we’re forced to waste another 6 bytes on the completely useless closing tag! That will not do.

Luckily, the closing tags are optional for <p> and <li> elements. We can rework our HTML structure to make use of this.

It may not validate, but it works. Who cares about validation anyway? 😉

8. Even More Perversion
Well, that’s probably the limit of size optimization. We need to specify the background color and width somehow, so we can’t completely eliminate the attributes. We could remove the quotes from attribute values and format our output like “<p c=1 w=ab>”, but that’s it. Right?

Actually, there is a way to compress the output even more. We can use the attribute name itself to specify pixel color and width. Observe :

Yes, that actually works. It even works in Internet Explorer 8 (when in standards mode).

9. Huffman And Friends
In any given image, some colors are more common than others. For example, a picture of a lush countryside might have a lot of greens, whereas a beach photo would be predominantly blue and yellow. Our current algorithm is not aware of that – it simply enumerates all colors in sequential order, assigning attribute names as it goes. There’s no relation between the color and the codename it gets.

We can reduce output size by assigning shorter attribute names to more common colors. This is known as Huffman coding, and is one of the simplest algorithms used for lossless data compression.

The general idea is thus :

Iterate over the image and record how many times each color is seen.

Sort the list of colors by their frequency.

Assign shorter names to more common colors, longer ones to rare ones.

In fact, we can use this idea to eliminate the color vs. width attribute distinction completely. Lets look at our HTML stucture again :

<p c1><p c16 w5><p cab><p ce2><p c1 w12><!-- ... -->

If we forget the “<p …>” wrappers for a moment…

c1 c16 w5 cab ce2 c1 w12

…it’s just a string of codes! Some more common, some less. We don’t need to know what each of them means to assign a optimally short and unique name to each one.

The actual implementation is somewhat complicated, but the HTML/CSS it produces is very space-efficient. This is what the output of my final algorithm looks like (line breaks inserted for clarity) :

Improve On That

Unbelievable though it may seem, this is still not the limit of size optimization for “pure CSS” images. For example, you could use variable-width right and left borders on the <p> element to encode additional pixels in a single element. This would decrease the HTML size at least by another 20%. You could also replace the primitive RLE algorithm I used in my converter with something more advanced. There might also be some interesting HTML hacks I haven’t even thought about.

This entry was posted on Wednesday, June 16th, 2010 at 19:47 and is filed under Fun Projects.
You can follow any responses to this entry through the RSS 2.0 feed.
You can leave a response, or trackback from your own site.

The resulting HTML+CSS is rather large, so in the vast majority of cases you’d be better off using a real image like .JPG or .PNG instead. This converter is mostly a fun proof-of-concept, not something you should seriously consider using on your sites.

Interesting but useless. It’s not possible to get smaller size of image after converting it from JPG to HMTL + CSS. Write application to convert JPG to SVG (SVG size smaller than JPG) – it’s theoretical possible but very hard. 😉 If you write it you’ll be my master. 😉

It is theoretically possible to get a smaller file if the input image is highly compressible, e.g. contains only large, simple shapes filled with the same colour. But yes, it’s still impractical for most inputs.

SVG is not inherently “smaller” than JPG. In fact, the two formats are not even directly comparable as they have different purposes. SVG is a vector graphics format, suitable for storing images constructed from a large number of simple geometric shapes – e.g. logos, icons, and so on. JPEG is a lossily compressed bitmap, best used for photos.

“SVG is not inherently “smaller” than JPG. In fact, the two formats are not even directly comparable as they have different purposes. SVG is (…)”
SVG – vector graphics, JPG – raster graphics, yes I know it. You don’t need to explain. 😉

“It is theoretically possible to get a smaller file if the input image is highly compressible, e.g. contains only large, simple shapes filled with the same colour.”
Like in your second and third image. It’s why I wrote my first comment. 😉

Search

This site uses cookies to improve your experience, to personalize ads and to analyze traffic. It also shares information about your use of this site with social media, advertising and analytics partners. By using this site, you agree to its use of cookies. AcceptSee Details