Warning: include(/home/content/j/e/f/jeffschiller/html/log.php) [function.include]: failed to open stream: No such file or directory in /home/content/68/6293468/html/blog/wp-content/themes/cd2010/header.php on line 9

Warning: include() [function.include]: Failed opening '/home/content/j/e/f/jeffschiller/html/log.php' for inclusion (include_path='.:/usr/local/php5/lib/php') in /home/content/68/6293468/html/blog/wp-content/themes/cd2010/header.php on line 9
Oh The Things You’ll Learn | CodeDread Blog

I was playing around with a new project recently and wanted to figure out the complementary color of a given color. All you need for this are the RGB values of the color for which you want to find the complement.

There are lots of ways of specifying a color on the Open Web:

  • rgb(255,0,0)
  • rgb(100%,0,0)
  • #FF0000
  • #F00
  • “red”

And it’s not just the 17 CSS color names, there are 147 cool-sounding extended color names like papayawhip. So given that a user can input a color in all sorts of ways, what’s the right way to do this?

The Hard Way

You can build a parser that determines the color format, parses hex and rgb strings and has a table that maps 147 strings to rgb triplets. It turns out there are a lot of JavaScript libraries that already do this. Here’s one.

But then I thought: why am I including yet another JavaScript library to do this parsing when the browser must already know how to map from hex, rgb or color name to an RGB triplet (or equivalent) in order to render the color in the first place? Surely there’s a way to extract this directly out of the DOM?

The DOM Way

It turns out there is. It’s called the CSS DOM and I always seem to forget about this document. Piecing together information from the SVG DOM and the CSS DOM, this is how you would get the red value of a fill attribute on a circle:

var red = someCircle.getPresentationAttribute("fill").rgbColor.red.getFloatValue(1);

That’s just a bit perverse, but at least it’s possible.

In testing this I was delighted to discover that Opera and WebKit let me do it. Sadly, Firefox does not.

The Best-Laid Plans…

Here’s where the plot thickens. Seems like the CSS Working Group was chartered to produce a new version of the CSS DOM to make the interfaces less clunky. Seems like the CSS WG sent out a notice strongly warning browsers not to implement certain DOM interfaces in the CSS DOM. Seems like it’s six years later and there’s no new document.

Unfortunately this is where my sad little tale ends. Erik of Opera suggests that the SVGT 1.2 uDOM is really the right way to do this. It doesn’t matter that I agree with him because I don’t think Webkit or Mozilla have any interest in implementing this any time soon.

It seems kind of sad that folks have to write JavaScript libraries to do color parsing when the browsers already do this natively. It also seems really weird that the SVG DOM interfaces extend obsolete CSS DOM interfaces (SVGColor extends CSSValue which Bert Bos mentions in his email).

#DOMFAIL ?

§539 · June 27, 2009 · Software, SVG, Technology, Web · Tags: , , , · [Print]

8 Comments to “Oh The Things You’ll Learn”

  1. CPKS says:

    getComputedColour = function(colour) {

    var d = document.createElement(‘DIV’);

    d.style.backgroundColor = colour;

    document.body.appendChild(d);

    if(window.getComputedStyle) { // Mozilla, Opera, Chrome, Safari

    var rtn = document.defaultView.getComputedStyle(d, null).getPropertyValue(‘background-color’);

    d.parentNode.removeChild(d);

    if (rtn.substr(0, 3) === “rgb”) rtn = rgb2Hex(rtn);

    return rtn;

    }

    else { // IE

    var rng = document.body.createTextRange();

    rng.moveToElementText(d);

    rng.execCommand(‘ForeColor’, false, colour);

    var iClr = rng.queryCommandValue(‘ForeColor’);

    var rgb = “rgb(“+(iClr & 0xFF)+”, “+((iClr & 0xFF00)>>8)+”, “+((iClr & 0xFF0000)>>16)+”)”;

    d.parentNode.removeChild(d);

    rng = null;

    return rgb2Hex(rgb);

    }

    }

  2. @CPKS: Ah, so getComputedStyle is another way, though it seems you may have to still parse from rgb() to hex for some browsers? Thanks a lot for this!

    That IE stuff is just disturbing to me. I don’t know what createTextRange(), moveToElementText(), execCommand() and queryCommandValue() really do. Lucky I don’t have to deal with it at the moment.

  3. CPKS says:

    Not pretty, is it? The incantations required to get IE to behave seem to become more recondite by the version: prior to IE8, the ‘BackColor’ command could be used to the same effect, but not any more: nous avons changé tout celà. Like you, I observe that it works and move on…

  4. James says:

    Propeller heads make things hard. Just open Adobe Illustrator, create a box, fill the box with your color, ask for the the complement from the color window and be done with it.

    James

  5. @James: Your solution sounds really intriguing! One thing I couldn’t figure out though: How could I get the web server to open up Adobe Illustrator when the user enters the color on the web page? 😉

  6. James says:

    Didnt know you wanted the web user to be able to do this. Of what goodly use is this function going to serve?

    James

  7. Originally I had thought to use the complement color so that I can safely show where the gradient stop is in the picker. After playing with this in the browsers that work, I realized it doesn’t really look that good so I’ll probably end up dropping the whole complement color.

    I’d still like to reliably be able to get the RGB components of a color input by the user though.

  8. Louie Holmes says:

    I always use Adobe illustrator at work because i work in an animation studio. this is really a serious tool for the graphic artist.;’~