Last active
April 3, 2018 22:21
-
-
Save danwalmsley/32720280917ef9f54d7df34dcf4c71b5 to your computer and use it in GitHub Desktop.
Class for Color Matrices in C#.
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
using System; | |
using System.Runtime.InteropServices; | |
namespace ColorMatrix | |
{ | |
public interface IColor | |
{ | |
byte R { get; set; } | |
byte G { get; set; } | |
byte B { get; set; } | |
byte A { get; set; } | |
} | |
[StructLayout(LayoutKind.Sequential)] | |
public sealed class ColorMatrix | |
{ | |
private ColorMatrix() | |
{ | |
/* | |
Identity | |
[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] | |
Translation | |
[1][0][0][0][0] | |
[0][1][0][0][0] | |
[0][0][1][0][0] | |
[0][0][0][1][0] | |
[1][1][1][0][1] | |
Swap Red and Blue | |
[0][0][1][0][0] | |
[0][1][0][0][0] | |
[1][0][0][0][0] | |
[0][0][0][1][0] | |
[1][1][1][0][1] | |
Subtract Green from Blue (shearing) | |
[1][0][0][0][0] | |
[0][1][0][0][0] | |
[0][-1][1][0][0] | |
[0][0][0][1][0] | |
[0][0][0][0][1] | |
*/ | |
//https://msdn.microsoft.com/en-us/library/windows/desktop/ms533809%28v=vs.85%29.aspx | |
} | |
public static ColorMatrix Identity => new ColorMatrix | |
{ | |
M00 = 1.0f, | |
M11 = 1.0f, | |
M22 = 1.0f, | |
M33 = 1.0f, | |
M44 = 1.0f | |
}; | |
public static ColorMatrix CreateScale (float redScale, float greenScale, float blueScale, float opacityScale) | |
{ | |
return new ColorMatrix | |
{ | |
M00 = redScale, | |
M11 = greenScale, | |
M22 = blueScale, | |
M33 = opacityScale | |
}; | |
} | |
public static ColorMatrix CreateHueRoation (double v) | |
{ | |
var a00 = (0.213) + (Math.Cos(v) * 0.787) - (Math.Sin(v) * 0.213); | |
var a01 = (0.715) - (Math.Cos(v) * 0.715) - (Math.Sin(v) * 0.715); | |
var a02 = (0.072) - (Math.Cos(v) * 0.072) + (Math.Sin(v) * 0.928); | |
var a10 = (0.213) - (Math.Cos(v) * 0.213) + (Math.Sin(v) * 0.143); | |
var a11 = (0.715) + (Math.Cos(v) * 0.285) + (Math.Sin(v) * 0.140); | |
var a12 = (0.072) - (Math.Cos(v) * 0.072) - (Math.Sin(v) * 0.283); | |
var a20 = (0.213) - (Math.Cos(v) * 0.213) - (Math.Sin(v) * 0.787); | |
var a21 = (0.715) - (Math.Cos(v) * 0.715) + (Math.Sin(v) * 0.715); | |
var a22 = (0.072) + (Math.Cos(v) * 0.928) + (Math.Sin(v) * 0.072); | |
return new ColorMatrix | |
{ | |
M00 = (float)a00, | |
M01 = (float)a01, | |
M02 = (float)a02, | |
M10 = (float)a10, | |
M11 = (float)a11, | |
M12 = (float)a12, | |
M20 = (float)a20, | |
M21 = (float)a21, | |
M22 = (float)a22, | |
M33 = 1 | |
}; | |
} | |
public static ColorMatrix CreateSaturation (float value) | |
{ | |
return new ColorMatrix | |
{ | |
M00 = 0.213f + 0.787f * value, M01 = 0.715f - 0.715f * value, M02 = 0.072f - 0.072f * value, | |
M10 = 0.213f - 0.213f * value, M11 = 0.715f + 0.285f * value, M12 = 0.072f - 0.072f * value, | |
M20 = 0.213f - 0.213f * value, M21 = 0.715f - 0.715f * value, M22 = 0.072f + 0.928f * value, | |
M33 = 1 | |
}; | |
} | |
public static ColorMatrix CreateLuminanceToAlpha () | |
{ | |
return new ColorMatrix | |
{ | |
M30 = 0.2125f, | |
M31 = 0.7154f, | |
M32 = 0.0721f | |
}; | |
} | |
public static ColorMatrix CreateInvert () | |
{ | |
return new ColorMatrix | |
{ | |
M00 = -1, | |
M11 = -1, | |
M22 = -1, | |
M33 = 1, | |
M03 = 255.0f, | |
M13 = 255.0f, | |
M23 = 255.0f, | |
}; | |
} | |
public static ColorMatrix CreateGreyscale () | |
{ | |
return new ColorMatrix | |
{ | |
M00 = 0.299f, | |
M01 = 0.587f, | |
M02 = 0.114f, | |
M10 = 0.299f, | |
M11 = 0.587f, | |
M12 = 0.114f, | |
M20 = 0.299f, | |
M21 = 0.587f, | |
M22 = 0.114f, | |
M33 = 1 | |
}; | |
} | |
public static ColorMatrix CreateBrightness (float value) | |
{ | |
var result = ColorMatrix.Identity; | |
result.M40 = value; | |
result.M41 = value; | |
result.M42 = value; | |
result.M43 = value; | |
return result; | |
} | |
public static ColorMatrix CreateExposure(float value) => new ColorMatrix | |
{ | |
M00 = value, | |
M11 = value, | |
M22 = value, | |
M33 = 1 | |
}; | |
public static ColorMatrix CreateContrast (float value) | |
{ | |
var n = (float) (0.5 * (1 - value)); | |
return new ColorMatrix | |
{ | |
M00 = value, M40 = n, | |
M11 = value, M41 = n, | |
M22 = value, M42 = n, | |
M33 = 1, | |
}; | |
} | |
// More filters here: | |
//https://github.com/skratchdot/color-matrix/blob/master/lib/filters.js | |
public float M00 { get; set; } | |
public float M01 { get; set; } | |
public float M02 { get; set; } | |
public float M03 { get; set; } | |
public float M04 { get; set; } | |
public float M10 { get; set; } | |
public float M11 { get; set; } | |
public float M12 { get; set; } | |
public float M13 { get; set; } | |
public float M14 { get; set; } | |
public float M20 { get; set; } | |
public float M21 { get; set; } | |
public float M22 { get; set; } | |
public float M23 { get; set; } | |
public float M24 { get; set; } | |
public float M30 { get; set; } | |
public float M31 { get; set; } | |
public float M32 { get; set; } | |
public float M33 { get; set; } | |
public float M34 { get; set; } | |
public float M40 { get; set; } | |
public float M41 { get; set; } | |
public float M42 { get; set; } | |
public float M43 { get; set; } | |
public float M44 { get; set; } | |
public ColorMatrix(float[][] newColorM) | |
{ | |
SetMatrix(newColorM); | |
} | |
internal void SetMatrix(float[][] newMatrix) | |
{ | |
M00 = newMatrix[0][0]; | |
M01 = newMatrix[0][1]; | |
M02 = newMatrix[0][2]; | |
M03 = newMatrix[0][3]; | |
M04 = newMatrix[0][4]; | |
M10 = newMatrix[1][0]; | |
M11 = newMatrix[1][1]; | |
M12 = newMatrix[1][2]; | |
M13 = newMatrix[1][3]; | |
M14 = newMatrix[1][4]; | |
M20 = newMatrix[2][0]; | |
M21 = newMatrix[2][1]; | |
M22 = newMatrix[2][2]; | |
M23 = newMatrix[2][3]; | |
M24 = newMatrix[2][4]; | |
M30 = newMatrix[3][0]; | |
M31 = newMatrix[3][1]; | |
M32 = newMatrix[3][2]; | |
M33 = newMatrix[3][3]; | |
M34 = newMatrix[3][4]; | |
M40 = newMatrix[4][0]; | |
M41 = newMatrix[4][1]; | |
M42 = newMatrix[4][2]; | |
M43 = newMatrix[4][3]; | |
M44 = newMatrix[4][4]; | |
} | |
internal float[][] GetMatrix() | |
{ | |
float[][] result = new float[5][]; | |
for (int i = 0; i < 5; i++) | |
result[i] = new float[5]; | |
result[0][0] = M00; | |
result[0][1] = M01; | |
result[0][2] = M02; | |
result[0][3] = M03; | |
result[0][4] = M04; | |
result[1][0] = M10; | |
result[1][1] = M11; | |
result[1][2] = M12; | |
result[1][3] = M13; | |
result[1][4] = M14; | |
result[2][0] = M20; | |
result[2][1] = M21; | |
result[2][2] = M22; | |
result[2][3] = M23; | |
result[2][4] = M24; | |
result[3][0] = M30; | |
result[3][1] = M31; | |
result[3][2] = M32; | |
result[3][3] = M33; | |
result[3][4] = M34; | |
result[4][0] = M40; | |
result[4][1] = M41; | |
result[4][2] = M42; | |
result[4][3] = M43; | |
result[4][4] = M44; | |
return result; | |
} | |
public float this[int row, int column] | |
{ | |
get | |
{ | |
return GetMatrix()[row][column]; | |
} | |
set | |
{ | |
float[][] tempM = GetMatrix(); | |
tempM[row][column] = value; | |
SetMatrix(tempM); | |
} | |
} | |
public bool Equals(ColorMatrix other) | |
{ | |
return M00 == other.M00 && | |
M01 == other.M01 && | |
M02 == other.M02 && | |
M03 == other.M03 && | |
M04 == other.M04 && | |
M10 == other.M10 && | |
M11 == other.M11 && | |
M12 == other.M12 && | |
M13 == other.M13 && | |
M14 == other.M14 && | |
M20 == other.M20 && | |
M21 == other.M21 && | |
M22 == other.M22 && | |
M23 == other.M23 && | |
M24 == other.M24 && | |
M30 == other.M30 && | |
M31 == other.M31 && | |
M32 == other.M32 && | |
M33 == other.M33 && | |
M34 == other.M34 && | |
M40 == other.M40 && | |
M41 == other.M41 && | |
M42 == other.M42 && | |
M43 == other.M43 && | |
M44 == other.M44; | |
} | |
private static ColorMatrix Multiply(float[][] matrix1, float[][] matrix2) | |
{ | |
int size = 5; // multiplies 2 5x5 matrices. | |
// build up an empty 5x5 array for results | |
float[][] result = new float[size][]; | |
for (int row = 0; row < size; row++) | |
{ | |
result[row] = new float[size]; | |
} | |
float[] column = new float[size]; | |
for (int j = 0; j < size; j++) | |
{ | |
for (int k = 0; k < size; k++) | |
{ | |
column[k] = matrix1[k][j]; | |
} | |
for (int i = 0; i < size; i++) | |
{ | |
float[] row = matrix2[i]; | |
float s = 0; | |
for (int k = 0; k < size; k++) | |
{ | |
s += row[k] * column[k]; | |
} | |
result[i][j] = s; | |
} | |
} | |
return new ColorMatrix(result); | |
} | |
public static ColorMatrix operator *(ColorMatrix value1, ColorMatrix value2) | |
{ | |
return Multiply(value1.GetMatrix(), value2.GetMatrix()); | |
} | |
public static bool operator ==(ColorMatrix value1, ColorMatrix value2) | |
{ | |
return value1.Equals(value2); | |
} | |
public static bool operator !=(ColorMatrix value1, ColorMatrix value2) | |
{ | |
return !value1.Equals(value2); | |
} | |
private byte Trim(float value) | |
{ | |
if(value < 0) | |
{ | |
return 0; | |
} | |
else if(value >255) | |
{ | |
return 255; | |
} | |
return (byte)value; | |
} | |
public void Apply(IColor o) | |
{ | |
var r = ((o.R * M00) + (o.G * M01) + (o.B * M02) + (o.A * M03) + (255 * M40)); | |
var g = ((o.R * M10) + (o.G * M11) + (o.B * M12) + (o.A * M13) + (255 * M41)); | |
var b = ((o.R * M20) + (o.G * M21) + (o.B * M22) + (o.A * M23) + (255 * M42)); | |
var a = ((o.R * M30) + (o.G * M31) + (o.B * M32) + (o.A * M33) + (255 * M43)); | |
o.R = Trim(r); | |
o.G = Trim(g); | |
o.B = Trim(b); | |
o.A = Trim(a); | |
} | |
public override int GetHashCode() | |
{ | |
return M00.GetHashCode() + M01.GetHashCode() + M02.GetHashCode() + M03.GetHashCode() + M04.GetHashCode() + | |
M10.GetHashCode() + M11.GetHashCode() + M12.GetHashCode() + M13.GetHashCode() + M14.GetHashCode() + | |
M20.GetHashCode() + M21.GetHashCode() + M22.GetHashCode() + M23.GetHashCode() + M24.GetHashCode() + | |
M30.GetHashCode() + M31.GetHashCode() + M32.GetHashCode() + M33.GetHashCode() + M34.GetHashCode() + | |
M40.GetHashCode() + M41.GetHashCode() + M42.GetHashCode() + M43.GetHashCode() + M44.GetHashCode(); | |
} | |
public override bool Equals(object obj) | |
{ | |
if (!(obj is ColorMatrix)) | |
{ | |
return false; | |
} | |
return Equals((ColorMatrix)obj); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment