Browse Source

Add Hue Fixes #262

Also fix sepia to conform to SVG spec


Former-commit-id: 9008d1d7849dc03c16877066b4e1d77fb944fce9
Former-commit-id: 5e70101c6ee320f0525021d4b42c8b7febc982f1
Former-commit-id: b36f5d0afa5baa727682012c395a0729b62c1419
pull/17/head
James Jackson-South 10 years ago
parent
commit
867c928bbe
  1. 4
      README.md
  2. 16
      src/ImageProcessor/Filters/ColorMatrix/ColorMatrixFilter.cs
  3. 33
      src/ImageProcessor/Filters/ColorMatrix/Hue.cs
  4. 5
      src/ImageProcessor/Filters/ColorMatrix/IColorMatrixFilter.cs
  5. 6
      src/ImageProcessor/Filters/ColorMatrix/Sepia.cs
  6. 25
      src/ImageProcessor/Filters/ImageFilterExtensions.cs
  7. 4
      tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs

4
README.md

@ -80,7 +80,7 @@ git clone https://github.com/JimBobSquarePants/ImageProcessor
- [x] Entropy Crop
- Rotation
- [ ] Flip (90, 270, FlipType etc. Need help) [#261](https://github.com/JimBobSquarePants/ImageProcessor/issues/261)
- [] Rotate by angle (Need help with Paeth approach) [#258](https://github.com/JimBobSquarePants/ImageProcessor/issues/258)
- [ ] Rotate by angle (Need help with Paeth approach) [#258](https://github.com/JimBobSquarePants/ImageProcessor/issues/258)
- ColorMatrix operations (Uses Matrix4x4)
- [x] BlackWhite
- [x] Greyscale BT709
@ -111,7 +111,7 @@ git clone https://github.com/JimBobSquarePants/ImageProcessor
- [x] Brightness
- [x] Pixelate
- [x] Saturation
- [ ] Hue [#262](https://github.com/JimBobSquarePants/ImageProcessor/issues/262)
- [x] Hue
- [x] Blend
- [ ] Mask
- Effects

16
src/ImageProcessor/Filters/ColorMatrix/ColorMatrixFilter.cs

@ -16,6 +16,9 @@ namespace ImageProcessor.Filters
/// <inheritdoc/>
public abstract Matrix4x4 Matrix { get; }
/// <inheritdoc/>
public virtual bool Compand => true;
/// <inheritdoc/>
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
{
@ -34,7 +37,7 @@ namespace ImageProcessor.Filters
{
for (int x = startX; x < endX; x++)
{
target[x, y] = ApplyMatrix(source[x, y], matrix);
target[x, y] = this.ApplyMatrix(source[x, y], matrix);
}
}
});
@ -48,9 +51,14 @@ namespace ImageProcessor.Filters
/// <returns>
/// The <see cref="Color"/>.
/// </returns>
private static Color ApplyMatrix(Color color, Matrix4x4 matrix)
private Color ApplyMatrix(Color color, Matrix4x4 matrix)
{
color = Color.InverseCompand(color);
bool compand = this.Compand;
if (compand)
{
color = Color.InverseCompand(color);
}
float sr = color.R;
float sg = color.G;
@ -60,7 +68,7 @@ namespace ImageProcessor.Filters
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 Color.Compand(color);
return compand ? Color.Compand(color) : color;
}
}
}

33
src/ImageProcessor/Filters/Hue.cs → src/ImageProcessor/Filters/ColorMatrix/Hue.cs

@ -36,31 +36,38 @@
/// <inheritdoc/>
public override Matrix4x4 Matrix => this.matrix;
/// <inheritdoc/>
public override bool Compand => false;
/// <inheritdoc/>
protected override void OnApply(ImageBase source, ImageBase target, Rectangle targetRectangle, Rectangle sourceRectangle)
{
float degrees = this.Angle;
double costheta = Math.Cos(degrees);
double sintheta = Math.Sin(degrees);
float radians = (float)ImageMaths.DegreesToRadians(this.Angle);
double cosradians = Math.Cos(radians);
double sinradians = Math.Sin(radians);
float lumR = .213f;
float lumG = .715f;
float lumB = .072f;
float oneMinusLumR = 1 - lumR;
float oneMinusLumG = 1 - lumG;
float oneMinusLumB = 1 - lumB;
// The matrix is set up to preserve the luminance of the image.
// See http://graficaobscura.com/matrix/index.html
// Number are taken from https://msdn.microsoft.com/en-us/library/jj192162(v=vs.85).aspx
// TODO: This isn't correct. Need to double check MS numbers against maths.
Matrix4x4 matrix4X4 = new Matrix4x4()
{
M11 = (float)(.213 + (costheta * .787) - (sintheta * .213)),
M12 = (float)(.715 - (costheta * .715) - (sintheta * .715)),
M13 = (float)(.072 - (costheta * .072) + (sintheta * .928)),
M21 = (float)(.213 - (costheta * .213) + (sintheta * .143)),
M22 = (float)(.715 + (costheta * .285) + (sintheta * .140)),
M23 = (float)(.072 - (costheta * .072) - (sintheta * .283)),
M31 = (float)(.213 - (costheta * .213) - (sintheta * .787)),
M32 = (float)(.715 - (costheta * .715) + (sintheta * .715)),
M33 = (float)(.072 + (costheta * .928) + (sintheta * .072))
M11 = (float)(+lumR + (cosradians * oneMinusLumR) - (sinradians * lumR)),
M12 = (float)(+lumR - (cosradians * lumR) - (sinradians * lumR)),
M13 = (float)(+lumR - (cosradians * lumR) - (sinradians * 0.787)),
M21 = (float)(+lumG - (cosradians * lumG) - (sinradians * lumG)),
M22 = (float)(+lumG + (cosradians * oneMinusLumG) + (sinradians * 0.140)),
M23 = (float)(+lumG - (cosradians * lumG) + (sinradians * lumG)),
M31 = (float)(+lumB - (cosradians * lumB) + (sinradians * oneMinusLumB)),
M32 = (float)(+lumB - (cosradians * lumB) - (sinradians * 0.283)),
M33 = (float)(+lumB + (cosradians * oneMinusLumB) + (sinradians * lumB))
};
this.matrix = matrix4X4;

5
src/ImageProcessor/Filters/ColorMatrix/IColorMatrixFilter.cs

@ -17,5 +17,10 @@ namespace ImageProcessor.Filters
/// Gets the <see cref="Matrix4x4"/> used to alter the image.
/// </summary>
Matrix4x4 Matrix { get; }
/// <summary>
/// Gets a value indicating whether to compand the value on processing.
/// </summary>
bool Compand { get; }
}
}

6
src/ImageProcessor/Filters/ColorMatrix/Sepia.cs

@ -8,7 +8,8 @@ namespace ImageProcessor.Filters
using System.Numerics;
/// <summary>
/// Converts the colors of the image to their sepia equivalent recreating an old photo effect.
/// Converts the colors of the image to their sepia equivalent.
/// The formula used matches the svg specification. <see href="http://www.w3.org/TR/filter-effects/#sepiaEquivalent"/>
/// </summary>
public class Sepia : ColorMatrixFilter
{
@ -25,5 +26,8 @@ namespace ImageProcessor.Filters
M32 = .168f,
M33 = .131f
};
/// <inheritdoc/>
public override bool Compand => false;
}
}

25
src/ImageProcessor/Filters/ImageFilterExtensions.cs

@ -209,6 +209,31 @@ namespace ImageProcessor.Filters
: source.Process(rectangle, new GreyscaleBt601());
}
/// <summary>
/// Alters the hue component of the image.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="degrees">The angle in degrees to adjust the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Hue(this Image source, float degrees)
{
return Hue(source, degrees, source.Bounds);
}
/// <summary>
/// Alters the hue component of the image.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="degrees">The angle in degrees to adjust the image.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Hue(this Image source, float degrees, Rectangle rectangle)
{
return source.Process(rectangle, new Hue(degrees));
}
/// <summary>
/// Inverts the colors of the image.
/// </summary>

4
tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs

@ -41,7 +41,9 @@ namespace ImageProcessor.Tests
{ "Sobel", new Sobel {Greyscale = true} },
{ "Pixelate", new Pixelate(8) },
{ "GuassianBlur", new GuassianBlur(10) },
{ "GuassianSharpen", new GuassianSharpen(10) }
{ "GuassianSharpen", new GuassianSharpen(10) },
{ "Hue-180", new Hue(180) },
{ "Hue--180", new Hue(-180) }
};
[Theory]

Loading…
Cancel
Save