<languageVersion : 1.0> // Based on “Color-Defective Vision and Computer Graphics Displays” written by Gary W. Meyer and Donald P. Greenberg // http://ieeexplore.ieee.org/iel1/38/408/00007759.pdf?arnumber=7759 kernel ColorBlindness < namespace : "Color Blindness"; vendor : "http://www.colorjack.com/"; version : 1; description : "This filter provides simulation of Protanopia, Deuteranopia, Tritanopia, and Achromatopsia."; > { input image4 src; output pixel4 dst; parameter int type < minValue: 0; maxValue: 3; defaultValue: 4; >; parameter float amount < minValue: 0.0; maxValue: 1.0; defaultValue: 1.0; >; const float3x3 RGB_XYZ = float3x3( // [M] in sRGB (D65) 0.412424, 0.212656, 0.0193324, 0.357579, 0.715158, 0.119193, 0.180464, 0.0721856, 0.950444 ); const float3x3 XYZ_RGB = float3x3( // -[M] in sRGB (D65) 3.24071, -0.969258, 0.0556352, -1.53726, 1.87599, -0.203996, -0.498571, 0.0415557, 1.05707 ); void evaluatePixel() { float4 o = sampleNearest(src, outCoord()); // source pixel float3 z = float3(o.r, o.g, o.b); // destination pixel float _x, _y, _m, _yi; if(type == 4) { // no changes (normal vision) dst.r = o.r * (1.0 - amount) + o.r * amount; dst.g = o.g * (1.0 - amount) + o.g * amount; dst.b = o.b * (1.0 - amount) + o.b * amount; dst.a = o.a; } else if(type == 3) { // convert to Monochrome using sRGB WhitePoint // monochrome z.r = z.g = z.b = (z.r * 0.212656 + z.g * 0.715158 + z.b * 0.072186); // anomylize colors z.r = o.r * (1.0 - amount) + z.r * amount; z.g = o.g * (1.0 - amount) + z.g * amount; z.b = o.b * (1.0 - amount) + z.b * amount; // record values dst.r = z.r; dst.g = z.g; dst.b = z.b; dst.a = o.a; } else { if(type == 0) { _x = 0.7465; _y = 0.2535; _m = 1.273463; _yi = -0.073894; } else if(type == 1) { _x = 1.4; _y = -0.4; _m = 0.968437; _yi = 0.003331; } else if(type == 2) { _x = 0.1748; _y = 0.0; _m = 0.062921; _yi = 0.292119; } // Convert source color into XYZ color space float3 XYZ = RGB_XYZ * float3(pow(o.r, 2.2), pow(o.g, 2.2), pow(o.b, 2.2)); // Convert XYZ into xyY — breaks down to Chromacity Coordinates (xy) and Luminance (L) float o_x = XYZ[0] / (XYZ[0] + XYZ[1] + XYZ[2]); float o_y = XYZ[1] / (XYZ[0] + XYZ[1] + XYZ[2]); float o_Y = XYZ[1]; // Generate the “Confusion Line” between the source color and the Confusion Point float m = (o_y - _y) / (o_x - _x); // slope of Confusion Line float yi = o_y - o_x * m; // y-intercept of Confusion Line (x-intercept = 0.0) // How far do the xy coords deviate from the selected type of Color Blindness? float change_x = (_yi - yi) / (m - _m); float change_y = (m * change_x) + yi; float change_Y = 0.0; // Compute the simulated color’s XYZ coords float z_X = change_x * o_Y / change_y; float z_Y = o_Y; float z_Z = (1.0 - (change_x + change_y)) * o_Y / change_y; // Difference between simulated color and neutral grey (in D65) float grey_X = 0.312713 * o_Y / 0.329016; float grey_Z = 0.358271 * o_Y / 0.329016; float3 diff = XYZ_RGB * float3(grey_X - z_X, 0.0, grey_Z - z_Z); // Compensate simulated color towards a neutral fit in RGB space z = XYZ_RGB * float3(z_X, z_Y, z_Z); // convert to RGB color space float _r = ((z.r < 0.0 ? 0.0 : 1.0) - z.r) / diff.r; float _g = ((z.g < 0.0 ? 0.0 : 1.0) - z.g) / diff.g; float _b = ((z.b < 0.0 ? 0.0 : 1.0) - z.b) / diff.b; float adjust = max((_r > 1.0 || _r < 0.0) ? 0.0 : _r, (_g > 1.0 || _g < 0.0) ? 0.0 : _g); adjust = max(adjust, (_b > 1.0 || _b < 0.0) ? 0.0 : _b); // now shift * all * three proportional to the greatest shift... z.r = z.r + (adjust * diff.r); z.g = z.g + (adjust * diff.g); z.b = z.b + (adjust * diff.b); // and then save the resulting simulated color... z.r = pow(z.r, 1.0 / 2.2); z.g = pow(z.g, 1.0 / 2.2); z.b = pow(z.b, 1.0 / 2.2); // anomylize colors z.r = o.r * (1.0 - amount) + z.r * amount; z.g = o.g * (1.0 - amount) + z.g * amount; z.b = o.b * (1.0 - amount) + z.b * amount; // return values dst.r = z.r; dst.g = z.g; dst.b = z.b; dst.a = o.a; } } }Required-plugin: