diff --git a/src/ImageProcessor/Filters/ColorMatrix/GreyscaleBt601.cs b/src/ImageProcessor/Filters/ColorMatrix/GreyscaleBt601.cs
index 90b1a9d8f..d10264c93 100644
--- a/src/ImageProcessor/Filters/ColorMatrix/GreyscaleBt601.cs
+++ b/src/ImageProcessor/Filters/ColorMatrix/GreyscaleBt601.cs
@@ -5,30 +5,35 @@
namespace ImageProcessor.Filters
{
+ using System.Numerics;
+
///
/// Converts the colors of the image to greyscale applying the formula as specified by
/// ITU-R Recommendation BT.601 .
///
- public class GreyscaleBt601 : ColorMatrixFilter
+ public class GreyscaleBt601 : MatrixFilter
{
///
- /// The inversion matrix.
+ /// The greyscale matrix.
///
- private static readonly ColorMatrix Matrix = new ColorMatrix(
- new[]
- {
- new float[] { 0.299f, 0.299f, 0.299f, 0, 0 },
- new float[] { 0.587f, 0.587f, 0.587f, 0, 0 },
- new float[] { 0.114f, 0.114f, 0.114f, 0, 0 },
- new float[] { 0, 0, 0, 1, 0 },
- new float[] { 0, 0, 0, 0, 1 }
- });
+ private static readonly Matrix4x4 Matrix = new Matrix4x4()
+ {
+ M11 = .299f,
+ M12 = .299f,
+ M13 = .299f,
+ M21 = .587f,
+ M22 = .587f,
+ M23 = .587f,
+ M31 = .114f,
+ M32 = .114f,
+ M33 = .114f
+ };
///
/// Initializes a new instance of the class.
///
public GreyscaleBt601()
- : base(Matrix, true)
+ : base(Matrix)
{
}
}
diff --git a/src/ImageProcessor/Filters/ColorMatrix/GreyscaleBt709.cs b/src/ImageProcessor/Filters/ColorMatrix/GreyscaleBt709.cs
index b975d33d7..8f59be7a2 100644
--- a/src/ImageProcessor/Filters/ColorMatrix/GreyscaleBt709.cs
+++ b/src/ImageProcessor/Filters/ColorMatrix/GreyscaleBt709.cs
@@ -5,30 +5,35 @@
namespace ImageProcessor.Filters
{
+ using System.Numerics;
+
///
/// Converts the colors of the image to greyscale applying the formula as specified by
/// ITU-R Recommendation BT.709 .
///
- public class GreyscaleBt709 : ColorMatrixFilter
+ public class GreyscaleBt709 : MatrixFilter
{
///
- /// The inversion matrix.
+ /// The greyscale matrix.
///
- private static readonly ColorMatrix Matrix = new ColorMatrix(
- new[]
- {
- new float[] { 0.2126f, 0.2126f, 0.2126f, 0, 0 },
- new float[] { 0.7152f, 0.7152f, 0.7152f, 0, 0 },
- new float[] { 0.0722f, 0.0722f, 0.0722f, 0, 0 },
- new float[] { 0, 0, 0, 1, 0 },
- new float[] { 0, 0, 0, 0, 1 }
- });
+ private static readonly Matrix4x4 Matrix = new Matrix4x4()
+ {
+ M11 = .2126f,
+ M12 = .2126f,
+ M13 = .2126f,
+ M21 = .7152f,
+ M22 = .7152f,
+ M23 = .7152f,
+ M31 = .0722f,
+ M32 = .0722f,
+ M33 = .0722f
+ };
///
/// Initializes a new instance of the class.
///
public GreyscaleBt709()
- : base(Matrix, true)
+ : base(Matrix)
{
}
}
diff --git a/src/ImageProcessor/Filters/ColorMatrix/Lomograph.cs b/src/ImageProcessor/Filters/ColorMatrix/Lomograph.cs
index f0d4c139a..895a9f2f9 100644
--- a/src/ImageProcessor/Filters/ColorMatrix/Lomograph.cs
+++ b/src/ImageProcessor/Filters/ColorMatrix/Lomograph.cs
@@ -5,30 +5,41 @@
namespace ImageProcessor.Filters
{
+ using System.Numerics;
+
///
/// Converts the colors of the image recreating an old Lomograph effect.
///
- public class Lomograph : ColorMatrixFilter
+ public class Lomograph : MatrixFilter
{
///
/// The Lomograph matrix. Purely artistic in composition.
/// TODO: Calculate a matrix that works in the linear color space.
///
- private static readonly ColorMatrix Matrix = new ColorMatrix(
- new[]
- {
- new[] { 1.50f, 0, 0, 0, 0 },
- new[] { 0, 1.45f, 0, 0, 0 },
- new[] { 0, 0, 1.09f, 0, 0 },
- new float[] { 0, 0, 0, 1, 0 },
- new[] { -0.10f, 0.05f, -0.08f, 0, 1 }
- });
+ private static readonly Matrix4x4 Matrix = new Matrix4x4()
+ {
+ M11 = 1.5f,
+ M22 = 1.45f,
+ M33 = 1.09f,
+ M41 = -.1f,
+ M42 = .0f,
+ M43 = -.08f
+ };
+ //private static readonly ColorMatrix Matrix = new ColorMatrix(
+ // new[]
+ // {
+ // new[] { 1.50f, 0, 0, 0, 0 },
+ // new[] { 0, 1.45f, 0, 0, 0 },
+ // new[] { 0, 0, 1.09f, 0, 0 },
+ // new float[] { 0, 0, 0, 1, 0 },
+ // new[] { -0.10f, 0.05f, -0.08f, 0, 1 }
+ // });
///
/// Initializes a new instance of the class.
///
public Lomograph()
- : base(Matrix, false)
+ : base(Matrix)
{
}
}
diff --git a/src/ImageProcessor/Filters/ColorMatrix/MatrixFilter.cs b/src/ImageProcessor/Filters/ColorMatrix/MatrixFilter.cs
new file mode 100644
index 000000000..2306af112
--- /dev/null
+++ b/src/ImageProcessor/Filters/ColorMatrix/MatrixFilter.cs
@@ -0,0 +1,77 @@
+//
+// Copyright (c) James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Filters
+{
+ using System.Numerics;
+ using System.Threading.Tasks;
+
+ ///
+ /// The color matrix filter.
+ ///
+ public class MatrixFilter : ParallelImageProcessor
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The to apply.
+ public MatrixFilter(Matrix4x4 matrix)
+ {
+ this.Value = matrix;
+ }
+
+ ///
+ /// Gets the matrix value.
+ ///
+ public Matrix4x4 Value { get; }
+
+ ///
+ protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
+ {
+ int sourceY = sourceRectangle.Y;
+ int sourceBottom = sourceRectangle.Bottom;
+ int startX = sourceRectangle.X;
+ int endX = sourceRectangle.Right;
+ Matrix4x4 matrix = this.Value;
+
+ Parallel.For(
+ startY,
+ endY,
+ y =>
+ {
+ if (y >= sourceY && y < sourceBottom)
+ {
+ for (int x = startX; x < endX; x++)
+ {
+ target[x, y] = ApplyMatrix(source[x, y], matrix);
+ }
+ }
+ });
+ }
+
+ ///
+ /// Applies the color matrix against the given color.
+ ///
+ /// The source color.
+ /// The matrix.
+ ///
+ /// The .
+ ///
+ private static Color ApplyMatrix(Color color, Matrix4x4 matrix)
+ {
+ color = PixelOperations.ToLinear(color);
+
+ float sr = color.R;
+ float sg = color.G;
+ float sb = color.B;
+
+ color.R = (sr * matrix.M11) + (sg * matrix.M21) + (sb * matrix.M31) + matrix.M41;
+ color.G = (sr * matrix.M12) + (sg * matrix.M22) + (sb * matrix.M32) + matrix.M42;
+ color.B = (sr * matrix.M13) + (sg * matrix.M23) + (sb * matrix.M33) + matrix.M43;
+
+ return PixelOperations.ToSrgb(color);
+ }
+ }
+}
diff --git a/src/ImageProcessor/Filters/ColorMatrix/Sepia.cs b/src/ImageProcessor/Filters/ColorMatrix/Sepia.cs
index 1b014a533..8628b8e81 100644
--- a/src/ImageProcessor/Filters/ColorMatrix/Sepia.cs
+++ b/src/ImageProcessor/Filters/ColorMatrix/Sepia.cs
@@ -5,30 +5,34 @@
namespace ImageProcessor.Filters
{
+ using System.Numerics;
+
///
/// Converts the colors of the image to their sepia equivalent recreating an old photo effect.
///
- public class Sepia : ColorMatrixFilter
+ public class Sepia : MatrixFilter
{
///
/// The sepia matrix.
- /// TODO: Calculate a matrix that works in the linear color space.
///
- private static readonly ColorMatrix Matrix = new ColorMatrix(
- new[]
- {
- new[] { .393f, .349f, .272f, 0, 0 },
- new[] { .769f, .686f, .534f, 0, 0 },
- new[] { .189f, .168f, .131f, 0, 0 },
- new float[] { 0, 0, 0, 1, 0 },
- new float[] { 0, 0, 0, 0, 1 }
- });
+ private static readonly Matrix4x4 Matrix = new Matrix4x4()
+ {
+ M11 = .393f,
+ M12 = .349f,
+ M13 = .272f,
+ M21 = .769f,
+ M22 = .686f,
+ M23 = .534f,
+ M31 = .189f,
+ M32 = .168f,
+ M33 = .131f
+ };
///
/// Initializes a new instance of the class.
///
public Sepia()
- : base(Matrix, false)
+ : base(Matrix)
{
}
}
diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj
index fdb70a183..48cd59e1d 100644
--- a/src/ImageProcessor/ImageProcessor.csproj
+++ b/src/ImageProcessor/ImageProcessor.csproj
@@ -48,6 +48,7 @@
+
diff --git a/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs b/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs
index ace61db0d..dfda1ef79 100644
--- a/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs
+++ b/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs
@@ -16,13 +16,13 @@ namespace ImageProcessor.Tests
//{ "Brightness--50", new Brightness(-50) },
//{ "Contrast-50", new Contrast(50) },
//{ "Contrast--50", new Contrast(-50) },
- { "Saturation-100", new Saturation(100) },
- { "Saturation--0", new Saturation(0) },
+ //{ "Saturation-100", new Saturation(100) },
+ //{ "Saturation--0", new Saturation(0) },
//{ "Alpha--50", new Alpha(50) },
//{ "Invert", new Invert() },
//{ "Sepia", new Sepia() },
//{ "BlackWhite", new BlackWhite() },
- //{ "Lomograph", new Lomograph() },
+ { "Lomograph", new Lomograph() },
//{ "Polaroid", new Polaroid() },
//{ "GreyscaleBt709", new GreyscaleBt709() },
//{ "GreyscaleBt601", new GreyscaleBt601() },
diff --git a/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs b/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs
index 9ece3b02b..6c33ef4c4 100644
--- a/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs
+++ b/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs
@@ -19,16 +19,16 @@ namespace ImageProcessor.Tests
///
public static readonly List Files = new List
{
- "../../TestImages/Formats/Jpg/Backdrop.jpg",
+ //"../../TestImages/Formats/Jpg/Backdrop.jpg",
"../../TestImages/Formats/Jpg/Calliphora.jpg",
- "../../TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg",
- "../../TestImages/Formats/Jpg/greyscale.jpg",
- "../../TestImages/Formats/Bmp/Car.bmp",
- "../../TestImages/Formats/Png/cmyk.png",
- "../../TestImages/Formats/Png/gamma-1.0-or-2.2.png",
- "../../TestImages/Formats/Png/splash.png",
- "../../TestImages/Formats/Gif/leaf.gif",
- "../../TestImages/Formats/Gif/rings.gif",
+ //"../../TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg",
+ //"../../TestImages/Formats/Jpg/greyscale.jpg",
+ //"../../TestImages/Formats/Bmp/Car.bmp",
+ //"../../TestImages/Formats/Png/cmyk.png",
+ //"../../TestImages/Formats/Png/gamma-1.0-or-2.2.png",
+ //"../../TestImages/Formats/Png/splash.png",
+ //"../../TestImages/Formats/Gif/leaf.gif",
+ //"../../TestImages/Formats/Gif/rings.gif",
//"../../TestImages/Formats/Gif/ani2.gif",
//"../../TestImages/Formats/Gif/giphy.gif"
};