mirror of https://github.com/SixLabors/ImageSharp
Browse Source
Former-commit-id: 390a36f397e55d0caeaca4d5353be432da1c96b9 Former-commit-id: a802e31bbbfe18164aa7f17b057bcf69d3f495b3 Former-commit-id: 6275da035cee61d2d7abf1da32acc7db5f6aae2dpull/1/head
6 changed files with 292 additions and 1 deletions
@ -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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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(); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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…
Reference in new issue