Skip to content

Instantly share code, notes, and snippets.

@danwalmsley
Last active April 3, 2018 22:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danwalmsley/32720280917ef9f54d7df34dcf4c71b5 to your computer and use it in GitHub Desktop.
Save danwalmsley/32720280917ef9f54d7df34dcf4c71b5 to your computer and use it in GitHub Desktop.
Class for Color Matrices in C#.
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