Tuesday, October 26, 2010

Desaturate an image -- without JavaScript + client side + cross browser

Introduction

so how to grayscale an arbitrary image at client side?

in Internet Explorer it's a one CSS liner:

#imgId { filter: gray }


In webkit and firefox there is currently -- in 2010 -- no way to desaturate an image solely with CSS.

So for a client side solution there is only 2 ways left: canvas and SVG. While the canvas solution is perfectly valid i feel the SVG solution to be more elegant, because with the SVG solution it's only html and css thus only markup language.


The solution

so how do i use SVG to desaturate my image?
basicaly it's only the following 3 snippets of code:

<svg height="0" width="0">
  <filter id="desaturate">
    <feColorMatrix type="matrix" values="0.3333 0.3333 0.3333 0 0
                                         0.3333 0.3333 0.3333 0 0
                                         0.3333 0.3333 0.3333 0 0
                                         0      0      0      1 0"/>
  </filter>
</svg>

and

<svg height="16" width="16">
  <image x="0" y="0" id="imgId" xlink:href="http://www.example.com/image.png" width="16" height="16">
</svg>

and following CSS code:

#imgId { filter:url(#desaturate) }


put the SVG filter element at any position in your html code, but be sure that it's displayed. so amongst others don't use "display: none". in order to hide the SVG element you can use height="0" and width="0" instead.

for firefox becarefull to use the right namespace for your SVG elements. hence be sure to use xhtml or to use the functions createElementNS and setAttributeNS.
If you go the xhtml way don't forget to:
-add following attributes to your html element:

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:svg="http://www.w3.org/2000/svg">

-set the extension of your html file to .xhtml

Arbitrary SVG effect on arbitrary html element?

what about using an arbitrary SVG effect on an arbitrary html element?
in firefox you can simply style any html element with any svg effect using CSS, see https://developer.mozilla.org/En/Applying_SVG_effects_to_HTML_content
in webkit you could use the <embed> element but unfortunately not all SVG effects works on embeded objects, e.g. see https://bugs.webkit.org/show_bug.cgi?id=44071

Resume

in internet explorer use the CSS filter property.
in webkit and firefox use a SVG filter element for the desaturation then use a SVG image element to load your image and finally apply the filter on the image with CSS.

for firefox and webkit you can see a live example on dooity.com -- look at the twitter and facebook icons in the footnote.

5 comments:

  1. very nice blog, man! continue to help us out with your nice articles, Birtoull!

    ReplyDelete
  2. This is awesome, more posts like this one :)

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. Hey man. Great post!

    I put together a tutorial that explains how to do this using only CSS/HTML. It makes use of the opacity and transition style declarations. With this, two images can create a "transition illusion" between themselves using the :hover pseudo-selector.

    Check it out and let me know what you think. You can find the tutorial here.

    ReplyDelete
  5. after practice, still not worked for blogger...hehehe
    but i can fixed...hohohoho
    ty ty ty

    ReplyDelete