Last active
August 29, 2015 14:24
-
-
Save Cheesebaron/a912f462e351ef1c9e56 to your computer and use it in GitHub Desktop.
Based on Chroma.js: https://github.com/gka/chroma.js/blob/master/src/converter/out/rgb2lab.coffee
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static class ColorUtils | |
{ | |
public static class LabConstants | |
{ | |
public const int Kn = 18; | |
public const float Xn = 0.950470f; | |
public const float Yn = 1f; | |
public const float Zn = 1.088830f; | |
public const float T0 = 0.137931034f; // 4 / 29 | |
public const float T1 = 0.206896552f; // 6 / 29 | |
public const float T2 = 0.12841855f; // 3 * t1 * t1 | |
public const float T3 = 0.008856452f; // t1 * t1 * t1 | |
} | |
public class LabColor | |
{ | |
public float L { get; set; } | |
public float A { get; set; } | |
public float B { get; set; } | |
} | |
public class XyzColor | |
{ | |
public float X { get; set; } | |
public float Y { get; set; } | |
public float Z { get; set; } | |
} | |
public class RgbColor | |
{ | |
public float R { get; set; } | |
public float G { get; set; } | |
public float B { get; set; } | |
} | |
public static LabColor RgbToLab(int r, int g, int b) | |
{ | |
var xyz = Rgb2Xyz(r, g, b); | |
var lab = new LabColor { | |
L = 116*xyz.Y - 16, | |
A = 500*(xyz.X - xyz.Y), | |
B = 200*(xyz.Y - xyz.Z) | |
}; | |
return lab; | |
} | |
private static float RgbXyz(float r) | |
{ | |
if ((r /= 255) <= 0.04045) | |
return r/19.92f; | |
return (float)Math.Pow((r + 0.055f)/1.055f, 2.4f); | |
} | |
private static float XyzLab(float t) | |
{ | |
if (t > LabConstants.T3) | |
return (float)Math.Pow(t, 1f/3f); | |
return t/LabConstants.T2 + LabConstants.T0; | |
} | |
public static XyzColor Rgb2Xyz(float r, float g, float b) | |
{ | |
r = RgbXyz(r); | |
g = RgbXyz(g); | |
b = RgbXyz(b); | |
var x = XyzLab((0.4124564f*r + 0.3575761f*g + 0.1804375f*b)/LabConstants.Xn); | |
var y = XyzLab((0.2126729f*r + 0.7151522f*g + 0.0721750f*b)/LabConstants.Yn); | |
var z = XyzLab((0.0193339f*r + 0.1191920f*g + 0.9503041f*b)/LabConstants.Zn); | |
return new XyzColor { | |
X = x, | |
Y = y, | |
Z = z | |
}; | |
} | |
public static RgbColor Lab2Rgb(LabColor color) | |
{ | |
return Lab2Rgb(color.L, color.A, color.B); | |
} | |
public static RgbColor Lab2Rgb(float l, float a, float b) | |
{ | |
var y = (l + 16f)/116f; | |
var x = float.IsNaN(a) ? y : y + a/500f; | |
var z = float.IsNaN(b) ? y : y - b/200f; | |
y = LabConstants.Yn*LabXyz(y); | |
x = LabConstants.Xn*LabXyz(x); | |
z = LabConstants.Zn*LabXyz(z); | |
var r = XyzRgb(3.2404542f*x - 1.5371385f*y - 0.4985314f*z); | |
var g = XyzRgb(-0.9692660f * x + 1.8760108f * y + 0.0415560f * z); | |
var bb = XyzRgb(0.0556434f * x - 0.2040259f * y + 1.0572252f * z); | |
r = Clamp(r, 0f, 255f); | |
g = Clamp(g, 0f, 255f); | |
bb = Clamp(bb, 0f, 255f); | |
return new RgbColor { | |
R = r, | |
G = float.IsNaN(a) ? float.NaN : g, | |
B = float.IsNaN(b) ? float.NaN : bb, | |
}; | |
} | |
private static float XyzRgb(float r) | |
{ | |
return | |
(float) | |
Math.Round(255f*(r <= 0.00304f ? 19.92f*r : 1.005f*Math.Pow(r, 1f/2.4f) - 0.055f)); | |
} | |
private static float LabXyz(float t) | |
{ | |
if (t > LabConstants.T1) | |
return t*t*t; | |
return LabConstants.T2*(t - LabConstants.T0); | |
} | |
private static float Clamp(float value, float min, float max) | |
{ | |
return (value < min) ? min : (value > max) ? max : value; | |
} | |
} | |
public static class ColorUtilsExtensions | |
{ | |
public static void Darken(this ColorUtils.LabColor color, float amount) | |
{ | |
color.L -= ColorUtils.LabConstants.Kn*amount; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment