private static bool CheckColor(LabColor color, PaletteOptions options) { var rgb = color.ToRgb(); var hcl = color.ToHcl(); var compLab = rgb.ToLab(); var labTolerance = 7; return( hcl.H >= options.HueMin && hcl.H <= options.HueMax && hcl.C >= options.ChromaMin && hcl.C <= options.ChromaMax && hcl.L >= options.LightMin && hcl.L <= options.LightMax && compLab.L >= (color.L - labTolerance) && compLab.L <= (color.L + labTolerance) && compLab.A >= (color.A - labTolerance) && compLab.A <= (color.A + labTolerance) && compLab.B >= (color.B - labTolerance) && compLab.B <= (color.B + labTolerance) ); }
// WARNING: may return [NaN, NaN, NaN] private LabColor Simulate(LabColor lab, ColorDistanceType type, int amount = 1) { // Cache var key = string.Format("{0}-{1}{2}", lab, type, amount); if (this.simulateCache.ContainsKey(key)) { return this.simulateCache[key]; } // Get data from type var confuse = ConfusionLine.Get(type); // Code adapted from http://galacticmilk.com/labs/Color-Vision/Javascript/Color.Vision.Simulate.js var color = lab.ToRgb(); var sr = color.R; var sg = color.G; var sb = color.B; double dr = sr; // destination color double dg = sg; double db = sb; // Convert source color into XYZ color space var pow_r = Math.Pow(sr, 2.2); var pow_g = Math.Pow(sg, 2.2); var pow_b = Math.Pow(sb, 2.2); var X = pow_r * 0.412424 + pow_g * 0.357579 + pow_b * 0.180464; // RGB->XYZ (sRGB:D65) var Y = pow_r * 0.212656 + pow_g * 0.715158 + pow_b * 0.0721856; var Z = pow_r * 0.0193324 + pow_g * 0.119193 + pow_b * 0.950444; // Convert XYZ into xyY Chromacity Coordinates (xy) and Luminance (Y) var chroma_x = X / (X + Y + Z); var chroma_y = Y / (X + Y + Z); // Generate the "Confusion Line" between the source color and the Confusion Point var m = (chroma_y - confuse.Y) / (chroma_x - confuse.X); // slope of Confusion Line var yint = chroma_y - chroma_x * m; // y-intercept of confusion line (x-intercept = 0.0) // How far the xy coords deviate from the simulation var deviate_x = (confuse.Yint - yint) / (m - confuse.M); var deviate_y = (m * deviate_x) + yint; // Compute the simulated color's XYZ coords X = deviate_x * Y / deviate_y; Z = (1.0 - (deviate_x + deviate_y)) * Y / deviate_y; // Neutral grey calculated from luminance (in D65) var neutral_X = 0.312713 * Y / 0.329016; var neutral_Z = 0.358271 * Y / 0.329016; // Difference between simulated color and neutral grey var diff_X = neutral_X - X; var diff_Z = neutral_Z - Z; var diff_r = diff_X * 3.24071 + diff_Z * -0.498571; // XYZ->RGB (sRGB:D65) var diff_g = diff_X * -0.969258 + diff_Z * 0.0415557; var diff_b = diff_X * 0.0556352 + diff_Z * 1.05707; // Convert to RGB color space dr = X * 3.24071 + Y * -1.53726 + Z * -0.498571; // XYZ->RGB (sRGB:D65) dg = X * -0.969258 + Y * 1.87599 + Z * 0.0415557; db = X * 0.0556352 + Y * -0.203996 + Z * 1.05707; // Compensate simulated color towards a neutral fit in RGB space var fit_r = ((dr < 0.0 ? 0.0 : 1.0) - dr) / diff_r; var fit_g = ((dg < 0.0 ? 0.0 : 1.0) - dg) / diff_g; var fit_b = ((db < 0.0 ? 0.0 : 1.0) - db) / diff_b; var adjust = Math.Max( // highest value Math.Max( (fit_r > 1.0 || fit_r < 0.0) ? 0.0 : fit_r, (fit_g > 1.0 || fit_g < 0.0) ? 0.0 : fit_g), (fit_b > 1.0 || fit_b < 0.0) ? 0.0 : fit_b ); // Shift proportional to the greatest shift dr = dr + (adjust * diff_r); dg = dg + (adjust * diff_g); db = db + (adjust * diff_b); // Apply gamma correction dr = Math.Pow(dr, 1.0 / 2.2); dg = Math.Pow(dg, 1.0 / 2.2); db = Math.Pow(db, 1.0 / 2.2); // Anomylize colors dr = sr * (1.0 - amount) + dr * amount; dg = sg * (1.0 - amount) + dg * amount; db = sb * (1.0 - amount) + db * amount; var dcolor = Color.FromArgb( (int)Math.Round(dr), (int)Math.Round(dg), (int)Math.Round(db)); var result = dcolor.ToLab(); this.simulateCache[key] = result; return result; }