Browse Source

Hue, Brightness

Former-commit-id: 390a36f397e55d0caeaca4d5353be432da1c96b9
Former-commit-id: a802e31bbbfe18164aa7f17b057bcf69d3f495b3
Former-commit-id: 6275da035cee61d2d7abf1da32acc7db5f6aae2d
pull/1/head
James Jackson-South 10 years ago
parent
commit
a3c1d1302f
  1. 60
      src/ImageProcessorCore/Filters/Brightness.cs
  2. 60
      src/ImageProcessorCore/Filters/Hue.cs
  3. 77
      src/ImageProcessorCore/Filters/Processors/BrightnessProcessor.cs
  4. 2
      src/ImageProcessorCore/Filters/Saturation.cs
  5. 47
      tests/ImageProcessorCore.Tests/Processors/Filters/BrightnessTest.cs
  6. 47
      tests/ImageProcessorCore.Tests/Processors/Filters/HueTest.cs

60
src/ImageProcessorCore/Filters/Brightness.cs

@ -0,0 +1,60 @@
// <copyright file="Brightness.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore
{
using Processors;
/// <summary>
/// Extension methods for the <see cref="Image{T,TP}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Alters the brightness component of the image.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="amount">The new brightness of the image. Must be between -100 and 100.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image{T,TP}"/>.</returns>
public static Image<T, TP> Brightness<T, TP>(this Image<T, TP> source, int amount, ProgressEventHandler progressHandler = null)
where T : IPackedVector<TP>
where TP : struct
{
return Brightness(source, amount, source.Bounds, progressHandler);
}
/// <summary>
/// Alters the brightness component of the image.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="amount">The new brightness of the image. Must be between -100 and 100.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image{T,TP}"/>.</returns>
public static Image<T, TP> Brightness<T, TP>(this Image<T, TP> source, int amount, Rectangle rectangle, ProgressEventHandler progressHandler = null)
where T : IPackedVector<TP>
where TP : struct
{
BrightnessProcessor<T, TP> processor = new BrightnessProcessor<T, TP>(amount);
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
}
}

60
src/ImageProcessorCore/Filters/Hue.cs

@ -0,0 +1,60 @@
// <copyright file="Hue.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore
{
using Processors;
/// <summary>
/// Extension methods for the <see cref="Image{T,TP}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Alters the hue component of the image.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="degrees">The angle in degrees to adjust the image.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image{T,TP}"/>.</returns>
public static Image<T, TP> Hue<T, TP>(this Image<T, TP> source, float degrees, ProgressEventHandler progressHandler = null)
where T : IPackedVector<TP>
where TP : struct
{
return Hue(source, degrees, source.Bounds, progressHandler);
}
/// <summary>
/// Alters the hue component of the image.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
/// <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>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image{T,TP}"/>.</returns>
public static Image<T, TP> Hue<T, TP>(this Image<T, TP> source, float degrees, Rectangle rectangle, ProgressEventHandler progressHandler = null)
where T : IPackedVector<TP>
where TP : struct
{
HueProcessor<T, TP> processor = new HueProcessor<T, TP>(degrees);
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
}
}

77
src/ImageProcessorCore/Filters/Processors/BrightnessProcessor.cs

@ -0,0 +1,77 @@
// <copyright file="BrightnessProcessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Processors
{
using System.Numerics;
using System.Threading.Tasks;
/// <summary>
/// An <see cref="IImageProcessor"/> to change the brightness of an <see cref="Image"/>.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class BrightnessProcessor<T, TP> : ImageProcessor<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <summary>
/// Initializes a new instance of the <see cref="BrightnessProcessor"/> class.
/// </summary>
/// <param name="brightness">The new brightness of the image. Must be between -100 and 100.</param>
/// <exception cref="ArgumentException">
/// <paramref name="brightness"/> is less than -100 or is greater than 100.
/// </exception>
public BrightnessProcessor(int brightness)
{
Guard.MustBeBetweenOrEqualTo(brightness, -100, 100, nameof(brightness));
this.Value = brightness;
}
/// <summary>
/// Gets the brightness value.
/// </summary>
public int Value { get; }
/// <inheritdoc/>
protected override void Apply(ImageBase<T, TP> target, ImageBase<T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
{
float brightness = this.Value / 100f;
int sourceY = sourceRectangle.Y;
int sourceBottom = sourceRectangle.Bottom;
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
using (IPixelAccessor<T, TP> sourcePixels = source.Lock())
using (IPixelAccessor<T, TP> targetPixels = target.Lock())
{
Parallel.For(
startY,
endY,
y =>
{
if (y >= sourceY && y < sourceBottom)
{
for (int x = startX; x < endX; x++)
{
// TODO: Check this with other formats.
Vector4 vector = sourcePixels[x, y].ToVector4().Expand();
Vector3 transformed = new Vector3(vector.X, vector.Y, vector.Z);
transformed += new Vector3(brightness);
vector = new Vector4(transformed.X, transformed.Y, transformed.Z, vector.W);
T packed = default(T);
packed.PackVector(vector.Compress());
targetPixels[x, y] = packed;
}
this.OnRowProcessed();
}
});
}
}
}
}

2
src/ImageProcessorCore/Filters/Saturation.cs

@ -1,7 +1,7 @@
// <copyright file="Saturation.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>-------------------------------------------------------------------------------------------------------------------
// </copyright>
namespace ImageProcessorCore
{

47
tests/ImageProcessorCore.Tests/Processors/Filters/BrightnessTest.cs

@ -0,0 +1,47 @@
// <copyright file="BrightnessTest.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Tests
{
using System.IO;
using Xunit;
public class BrightnessTest : FileTestBase
{
public static readonly TheoryData<int> BrightnessValues
= new TheoryData<int>
{
50 ,
-50 ,
};
[Theory]
[MemberData("BrightnessValues")]
public void ImageShouldApplyBrightnessFilter(int value)
{
const string path = "TestOutput/Brightness";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
string filename = Path.GetFileNameWithoutExtension(file) + "-" + value + Path.GetExtension(file);
Image image = new Image(stream);
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.Brightness(value)
.Save(output);
}
}
}
}
}
}

47
tests/ImageProcessorCore.Tests/Processors/Filters/HueTest.cs

@ -0,0 +1,47 @@
// <copyright file="HueTest.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Tests
{
using System.IO;
using Xunit;
public class HueTest : FileTestBase
{
public static readonly TheoryData<int> HueValues
= new TheoryData<int>
{
180 ,
-180 ,
};
[Theory]
[MemberData("HueValues")]
public void ImageShouldApplyHueFilter(int value)
{
const string path = "TestOutput/Hue";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
string filename = Path.GetFileNameWithoutExtension(file) + "-" + value + Path.GetExtension(file);
Image image = new Image(stream);
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.Hue(value)
.Save(output);
}
}
}
}
}
}
Loading…
Cancel
Save