mirror of https://github.com/SixLabors/ImageSharp
55 changed files with 372 additions and 316 deletions
@ -0,0 +1,47 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Numerics; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing.Processors; |
|||
using SixLabors.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// Extension methods for the <see cref="Image{TPixel}"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Filters an image but the given color matrix
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="matrix">The filter color matrix</param>
|
|||
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
|
|||
public static IImageProcessingContext<TPixel> Filter<TPixel>(this IImageProcessingContext<TPixel> source, Matrix4x4 matrix) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
source.ApplyProcessor(new FilterProcessor<TPixel>(matrix)); |
|||
return source; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Filters an image but the given color matrix
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="matrix">The filter color matrix</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{TPixel}"/>.</returns>
|
|||
public static IImageProcessingContext<TPixel> Filter<TPixel>(this IImageProcessingContext<TPixel> source, Matrix4x4 matrix, Rectangle rectangle) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
source.ApplyProcessor(new FilterProcessor<TPixel>(matrix), rectangle); |
|||
return source; |
|||
} |
|||
} |
|||
} |
|||
@ -1,34 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Numerics; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors |
|||
{ |
|||
/// <summary>
|
|||
/// Converts the colors of the image recreating Achromatomaly (Color desensitivity) color blindness.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal class AchromatomalyProcessor<TPixel> : ColorMatrixProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override Matrix4x4 Matrix => new Matrix4x4 |
|||
{ |
|||
M11 = .618F, |
|||
M12 = .163F, |
|||
M13 = .163F, |
|||
M21 = .320F, |
|||
M22 = .775F, |
|||
M23 = .320F, |
|||
M31 = .062F, |
|||
M32 = .062F, |
|||
M33 = .516F, |
|||
M44 = 1 |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Compand => false; |
|||
} |
|||
} |
|||
@ -1,34 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Numerics; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors |
|||
{ |
|||
/// <summary>
|
|||
/// Converts the colors of the image recreating Achromatopsia (Monochrome) color blindness.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal class AchromatopsiaProcessor<TPixel> : ColorMatrixProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override Matrix4x4 Matrix => new Matrix4x4 |
|||
{ |
|||
M11 = .299F, |
|||
M12 = .299F, |
|||
M13 = .299F, |
|||
M21 = .587F, |
|||
M22 = .587F, |
|||
M23 = .587F, |
|||
M31 = .114F, |
|||
M32 = .114F, |
|||
M33 = .114F, |
|||
M44 = 1 |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Compand => false; |
|||
} |
|||
} |
|||
@ -1,31 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Numerics; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors |
|||
{ |
|||
/// <summary>
|
|||
/// Converts the colors of the image recreating Protanopia (Red-Weak) color blindness.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal class ProtanomalyProcessor<TPixel> : ColorMatrixProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override Matrix4x4 Matrix => new Matrix4x4 |
|||
{ |
|||
M11 = 0.817F, |
|||
M12 = 0.333F, |
|||
M21 = 0.183F, |
|||
M22 = 0.667F, |
|||
M23 = 0.125F, |
|||
M33 = 0.875F, |
|||
M44 = 1 |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Compand => false; |
|||
} |
|||
} |
|||
@ -1,78 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Threading.Tasks; |
|||
using SixLabors.ImageSharp.Advanced; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors |
|||
{ |
|||
/// <summary>
|
|||
/// The color matrix filter. Inherit from this class to perform operation involving color matrices.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal abstract class ColorMatrixProcessor<TPixel> : ImageProcessor<TPixel>, IColorMatrixProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public abstract Matrix4x4 Matrix { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
public virtual bool Compand { get; set; } = true; |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration) |
|||
{ |
|||
int startY = sourceRectangle.Y; |
|||
int endY = sourceRectangle.Bottom; |
|||
int startX = sourceRectangle.X; |
|||
int endX = sourceRectangle.Right; |
|||
|
|||
// Align start/end positions.
|
|||
int minX = Math.Max(0, startX); |
|||
int maxX = Math.Min(source.Width, endX); |
|||
int minY = Math.Max(0, startY); |
|||
int maxY = Math.Min(source.Height, endY); |
|||
|
|||
// Reset offset if necessary.
|
|||
if (minX > 0) |
|||
{ |
|||
startX = 0; |
|||
} |
|||
|
|||
if (minY > 0) |
|||
{ |
|||
startY = 0; |
|||
} |
|||
|
|||
Matrix4x4 matrix = this.Matrix; |
|||
bool compand = this.Compand; |
|||
|
|||
Parallel.For( |
|||
minY, |
|||
maxY, |
|||
configuration.ParallelOptions, |
|||
y => |
|||
{ |
|||
Span<TPixel> row = source.GetPixelRowSpan(y - startY); |
|||
|
|||
for (int x = minX; x < maxX; x++) |
|||
{ |
|||
ref TPixel pixel = ref row[x - startX]; |
|||
var vector = pixel.ToVector4(); |
|||
|
|||
if (compand) |
|||
{ |
|||
vector = vector.Expand(); |
|||
} |
|||
|
|||
vector = Vector4.Transform(vector, matrix); |
|||
pixel.PackFromVector4(compand ? vector.Compress() : vector); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Numerics; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors |
|||
{ |
|||
/// <summary>
|
|||
/// Encapsulates properties and methods for creating processors that utilize a matrix to
|
|||
/// alter the image pixels.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal interface IColorMatrixProcessor<TPixel> : IImageProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the <see cref="Matrix4x4"/> used to alter the image.
|
|||
/// </summary>
|
|||
Matrix4x4 Matrix { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating whether to compress or expand individual pixel color values on processing.
|
|||
/// </summary>
|
|||
bool Compand { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors |
|||
{ |
|||
/// <summary>
|
|||
/// Converts the colors of the image recreating Achromatomaly (Color desensitivity) color blindness.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal class AchromatomalyProcessor<TPixel> : FilterProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="AchromatomalyProcessor{TPixel}"/> class.
|
|||
/// </summary>
|
|||
public AchromatomalyProcessor() |
|||
: base(MatrixFilters.AchromatomalyFilter) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors |
|||
{ |
|||
/// <summary>
|
|||
/// Converts the colors of the image recreating Achromatopsia (Monochrome) color blindness.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal class AchromatopsiaProcessor<TPixel> : FilterProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="AchromatopsiaProcessor{TPixel}"/> class.
|
|||
/// </summary>
|
|||
public AchromatopsiaProcessor() |
|||
: base(MatrixFilters.AchromatopsiaFilter) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors |
|||
{ |
|||
/// <summary>
|
|||
/// Converts the colors of the image recreating Protanomaly (Red-Weak) color blindness.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal class ProtanomalyProcessor<TPixel> : FilterProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ProtanomalyProcessor{TPixel}"/> class.
|
|||
/// </summary>
|
|||
public ProtanomalyProcessor() |
|||
: base(MatrixFilters.ProtanomalyFilter) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.Processing; |
|||
using SixLabors.ImageSharp.Processing.Processors; |
|||
using Xunit; |
|||
|
|||
namespace SixLabors.ImageSharp.Tests.Processing.Filters |
|||
{ |
|||
public class FilterTest : BaseImageOperationsExtensionTest |
|||
{ |
|||
[Fact] |
|||
public void Filter_CorrectProcessor() |
|||
{ |
|||
this.operations.Filter(MatrixFilters.AchromatomalyFilter * MatrixFilters.CreateHueFilter(90F)); |
|||
FilterProcessor<Rgba32> p = this.Verify<FilterProcessor<Rgba32>>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Filter_rect_CorrectProcessor() |
|||
{ |
|||
this.operations.Filter(MatrixFilters.AchromatomalyFilter * MatrixFilters.CreateHueFilter(90F), this.rect); |
|||
FilterProcessor<Rgba32> p = this.Verify<FilterProcessor<Rgba32>>(this.rect); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing; |
|||
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; |
|||
|
|||
using SixLabors.Primitives; |
|||
using Xunit; |
|||
|
|||
namespace SixLabors.ImageSharp.Tests.Processing.Processors.Filters |
|||
{ |
|||
public class FilterTest : FileTestBase |
|||
{ |
|||
[Theory] |
|||
[WithFileCollection(nameof(DefaultFiles), DefaultPixelType)] |
|||
public void ImageShouldApplyFilter<TPixel>(TestImageProvider<TPixel> provider) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
using (Image<TPixel> image = provider.GetImage()) |
|||
{ |
|||
image.Mutate(x => x.Filter(MatrixFilters.CreateBrightnessFilter(1.2F) * MatrixFilters.CreateContrastFilter(1.2F))); |
|||
image.DebugSave(provider); |
|||
} |
|||
} |
|||
|
|||
[Theory] |
|||
[WithFileCollection(nameof(DefaultFiles), DefaultPixelType)] |
|||
public void ImageShouldApplyFilterInBox<TPixel>(TestImageProvider<TPixel> provider) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
using (Image<TPixel> source = provider.GetImage()) |
|||
using (Image<TPixel> image = source.Clone()) |
|||
{ |
|||
var bounds = new Rectangle(10, 10, image.Width / 2, image.Height / 2); |
|||
|
|||
image.Mutate(x => x.Filter(MatrixFilters.CreateBrightnessFilter(1.2F) * MatrixFilters.CreateContrastFilter(1.2F), bounds)); |
|||
image.DebugSave(provider); |
|||
|
|||
ImageComparer.Tolerant().VerifySimilarityIgnoreRegion(source, image, bounds); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue