Skip to content

Instantly share code, notes, and snippets.

@Cheesebaron
Last active August 29, 2015 14:24
Show Gist options
  • Save Cheesebaron/a912f462e351ef1c9e56 to your computer and use it in GitHub Desktop.
Save Cheesebaron/a912f462e351ef1c9e56 to your computer and use it in GitHub Desktop.
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