Rendering Images With CSS3 Drop Shadow

Profile picture for user AlexH
Alex Hripak
Senior Developer

This past month a tool was open sourced on github called image2css, which is a simple PHP class that takes an image and converts it to CSS3 box-shadow. The creator posted a version of the Mona Lisa in pure CSS. That’s an interesting concept, but why not do it all on the client side and let the server be? This is very possible with some newer web technologies, namely canvas and the JavaScript functions that come with it. Following the steps outlined below, augmented with some Drupal themeing and configuration, I built this tool: image2css

Building the page

My CMS I used was Drupal of course, which is the primary platform we develop on here at left-click. But since Drupal 7 doesn’t ship with some of the element types I’d like to use, such as Range or Number, we’ll need some help from the HTML5 Tools module. This module exposes those new types of elements as Form API types. So I pop those form items into a custom form and save this for later when we have JavaScript to add. I’ll also write a quick hook_block_info() and hook_block_content() so the form will be available as a block for use in Panels.

Reading the file

I need to get the file from the user in a somewhat easy way, and I have the input type=”file” readily available. But how do I read the data from this without involving the server? I could write a custom wrapper around the FileReader object and write my own ProgressEvent handlers to process it, but this would be one more item to maintain. Instead, I used a nice library (in this case, filereader.js) which does just that and more, all while exposing it as a jQuery method. This library provides three different ways to accept files: traditional file input, drop zone, and clipboard—but I will only be using the file input. Once the file is loaded it’s available as base64 encoded data.

The magic

Now that I have our image file available, I can read the base64 data into the src attribute of some <img /> tag and then write that image into the canvas element. Once the canvas is ready, I can use the getImageData function to read an array of rgba values that make up this canvas. So with the array in hand we split it up into rows and columns, then store each pixel as a box-shadow value into some array or string. Every four values in the array represents an rgba value, so a column is really four values wide. And that’s it, the result can be used as box-shadow for an element on the page.

Final thoughts

You may be asking at this point, is this practical. Short answer? No. Just like how the older image to HTML table converters served no real purpose. But it’s all about pushing the limits of client side functionality. The web is full of new and interesting projects on the client side such as node.js or and this all comes with our clients having much more processing power than around five years ago. But what this concept absolutely alludes to is the fact that really complex designs can be accomplished with CSS while using a minimal amount of images. Of course, it comes at the price of inaccessibility for those who are stuck on older browsers. Small disclaimer that it does utilize new technologies that Internet Explorer and older browsers may not support, and trying to convert large images will crash your window. These are the limits of client side processing. But it’s still fun! Give the tool I built a try at! 

comments powered by Disqus