Color Blindness Simulation and introducing… <canvas> ColorMatrix!
Introducing the Javascript Color Matrix Library. It’s a very simple example of the most basic ColorMatrix formulas — partially inspired by Quasimondo’s wonderful Flash 8 ColorMatrix Class. Today, we’ll be combining the Color Blindness library along with a <canvas> implementation of ColorMatrix. So now, just like in Actionscript, you can apply photoshop-like filters to <canvas>.

Requires <canvas> getImageData() & putImageData() support — Firefox (2.0+), Opera (9.5+), and Webkit.

How to simulate color blindness (for accessibility)

The most obvious way would be to do the calculations in CIE XYZ using confusion lines, however, <canvas> uses RGB. So you’d have to convert from XYZ to RGB, run the confusion lines, then convert back to RGB. Here’s an example of what that looks like: Color Blindness Library — It’s great for running on a few colors, but too slow for larger images.

Matrix’s are generally about as quick as you’re going to get for generic color filters, so that’s what I’ve converted the formulas into – compliant with Actionscript’s ColorMatrix, and other programming languages that use standard RGBA matrix’s. Also, I’ve converted them into color transform’s which are useful in Actionscript (ColorTransform), Pixelmator (Image... Channel Mixer), and Photoshop (Image... Adjustments... Channel Mixer).

I used data generated by Matthew Wickline’s formulas to base my blindness library. My script triangulates the hue by comparing the un-filtered, completely saturated, RGB values with the same value after they’d been run through Wickline’s formula. The code can be viewed in this .html’s source!

Want to use these blindness filters in Photoshop, or Pixelmator? Use these values in Channel Mixer:

{Normal:{ R:[100, 0, 0], G:[0, 100, 0], B:[0, 100, 0]},
 Protanopia:{ R:[56.667, 43.333, 0], G:[55.833, 44.167, 0], B:[0, 24.167, 75.833]},
 Protanomaly:{ R:[81.667, 18.333, 0], G:[33.333, 66.667, 0], B:[0, 12.5, 87.5]},
 Deuteranopia:{ R:[62.5, 37.5, 0], G:[70, 30, 0], B:[0, 30, 70]},
 Deuteranomaly:{ R:[80, 20, 0], G:[25.833, 74.167, 0], B:[0, 14.167, 85.833]},
 Tritanopia:{ R:[95, 5, 0], G:[0, 43.333, 56.667], B:[0, 47.5, 52.5]},
 Tritanomaly:{ R:[96.667, 3.333, 0], G:[0, 73.333, 26.667], B:[0, 18.333, 81.667]},
 Achromatopsia:{ R:[29.9, 58.7, 11.4], G:[29.9, 58.7, 11.4], B:[29.9, 58.7, 11.4]},
 Achromatomaly:{ R:[61.8, 32, 6.2], G:[16.3, 77.5, 6.2], B:[16.3, 32.0, 51.6]}
Let’s take Protanopia for example:

The values are: { R:[56.667, 43.333, 0], G:[55.833, 44.167, 0], B:[0, 24.167, 75.833]}

‘R’, ‘G’, and ‘B’ contain array’s of the corresponding Red, Green, and Blue values for each Channel.

So, for the Red Channel we’d shift the Red Value up 56.667% (from the default position), and Green we’d shift up 43.333%… and since the last value is zero, we don’t change the Blue Value.

Ok, so now just do the same thing for the Green and Blue channels, and you’re set!

Alright, so how does a ColorMatrix work?
ColorMatrix=function(o,m) { // takes: RGBA object, Matrix array

    function fu(n) { return(n<0?0:(n<255?n:255)); }

    var r=((o.R*m[0])+(o.G*m[1])+(o.B*m[2])+(o.A*m[3])+m[4]);
    var g=((o.R*m[5])+(o.G*m[6])+(o.B*m[7])+(o.A*m[8])+m[9]);
    var b=((o.R*m[10])+(o.G*m[11])+(o.B*m[12])+(o.A*m[13])+m[14]);
    var a=((o.R*m[15])+(o.G*m[16])+(o.B*m[17])+(o.A*m[18])+m[19]);
    return({'R':fu(r), 'G':fu(g), 'B':fu(b), 'A':fu(a)});

Blind=function(v) { // this function just returns the Matrix

    return({'Normal':[1,0,0,0,0, 0,1,0,0,0, 0,0,1,0,0, 0,0,0,1,0, 0,0,0,0,1],
            'Protanopia':[0.567,0.433,0,0,0, 0.558,0.442,0,0,0, 0,0.242,0.758,0,0, 0,0,0,1,0, 0,0,0,0,1],
            'Protanomaly':[0.817,0.183,0,0,0, 0.333,0.667,0,0,0, 0,0.125,0.875,0,0, 0,0,0,1,0, 0,0,0,0,1],
            'Deuteranopia':[0.625,0.375,0,0,0, 0.7,0.3,0,0,0, 0,0.3,0.7,0,0, 0,0,0,1,0, 0,0,0,0,1],
            'Deuteranomaly':[0.8,0.2,0,0,0, 0.258,0.742,0,0,0, 0,0.142,0.858,0,0, 0,0,0,1,0, 0,0,0,0,1],
            'Tritanopia':[0.95,0.05,0,0,0, 0,0.433,0.567,0,0, 0,0.475,0.525,0,0, 0,0,0,1,0, 0,0,0,0,1],
            'Tritanomaly':[0.967,0.033,0,0,0, 0,0.733,0.267,0,0, 0,0.183,0.817,0,0, 0,0,0,1,0, 0,0,0,0,1],
            'Achromatopsia':[0.299,0.587,0.114,0,0, 0.299,0.587,0.114,0,0, 0.299,0.587,0.114,0,0, 0,0,0,1,0, 0,0,0,0,1],
            'Achromatomaly':[0.618,0.320,0.062,0,0, 0.163,0.775,0.062,0,0, 0.163,0.320,0.516,0,0,0,0,0,1,0,0,0,0,0]}[v]);


/* Here we are calling the function */

ColorMatrix({R:255, G:0, B:0}, Blind['Tritanopia']);
Suggestions, and Conclusion

That’s basically the function you’d use to apply a ColorMatrix filter on a red pixel. You’d want to make a few optimizations (feel free to look at the source code for this demo, which has a few optimization in place).

If you have any thoughts on the matter, leave your comment here.