mirror of https://github.com/SixLabors/ImageSharp
committed by
GitHub
97 changed files with 549 additions and 943 deletions
@ -0,0 +1,29 @@ |
|||
// <copyright file="ArrayExtensions.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// Extension methods for arrays.
|
|||
/// </summary>
|
|||
public static class ArrayExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Locks the pixel buffer providing access to the pixels.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|||
/// <param name="pixels">The pixel buffer.</param>
|
|||
/// <param name="width">Gets the width of the image represented by the pixel buffer.</param>
|
|||
/// <param name="height">The height of the image represented by the pixel buffer.</param>
|
|||
/// <returns>The <see cref="PixelAccessor{TColor,TPacked}"/></returns>
|
|||
public static PixelAccessor<TColor, TPacked> Lock<TColor, TPacked>(this TColor[] pixels, int width, int height) |
|||
where TColor : struct, IPackedPixel<TPacked> |
|||
where TPacked : struct |
|||
{ |
|||
return new PixelAccessor<TColor, TPacked>(width, height, pixels); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,68 @@ |
|||
// <copyright file="CropProcessor.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Processors |
|||
{ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
|
|||
/// <summary>
|
|||
/// Provides methods to allow the cropping of an image.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|||
public class CropProcessor<TColor, TPacked> : ImageFilteringProcessor<TColor, TPacked> |
|||
where TColor : struct, IPackedPixel<TPacked> |
|||
where TPacked : struct |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="CropProcessor{TColor,TPacked}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="cropRectangle">The target cropped rectangle.</param>
|
|||
public CropProcessor(Rectangle cropRectangle) |
|||
{ |
|||
this.CropRectangle = cropRectangle; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the width.
|
|||
/// </summary>
|
|||
public Rectangle CropRectangle { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void Apply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
if (this.CropRectangle == sourceRectangle) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
int minY = Math.Max(this.CropRectangle.Y, startY); |
|||
int maxY = Math.Min(this.CropRectangle.Bottom, endY); |
|||
int minX = Math.Max(this.CropRectangle.X, sourceRectangle.X); |
|||
int maxX = Math.Min(this.CropRectangle.Right, sourceRectangle.Right); |
|||
|
|||
TColor[] target = new TColor[this.CropRectangle.Width * this.CropRectangle.Height]; |
|||
|
|||
using (PixelAccessor<TColor, TPacked> sourcePixels = source.Lock()) |
|||
using (PixelAccessor<TColor, TPacked> targetPixels = target.Lock<TColor, TPacked>(this.CropRectangle.Width, this.CropRectangle.Height)) |
|||
{ |
|||
Parallel.For( |
|||
minY, |
|||
maxY, |
|||
this.ParallelOptions, |
|||
y => |
|||
{ |
|||
for (int x = minX; x < maxX; x++) |
|||
{ |
|||
targetPixels[x - minX, y - minY] = sourcePixels[x, y]; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
source.SetPixels(this.CropRectangle.Width, this.CropRectangle.Height, target); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,59 @@ |
|||
// <copyright file="EntropyCropProcessor.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Processors |
|||
{ |
|||
/// <summary>
|
|||
/// Provides methods to allow the cropping of an image to preserve areas of highest
|
|||
/// entropy.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|||
public class EntropyCropProcessor<TColor, TPacked> : ImageFilteringProcessor<TColor, TPacked> |
|||
where TColor : struct, IPackedPixel<TPacked> |
|||
where TPacked : struct |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="EntropyCropProcessor{TColor, TPacked}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="threshold">The threshold to split the image. Must be between 0 and 1.</param>
|
|||
/// <exception cref="System.ArgumentException">
|
|||
/// <paramref name="threshold"/> is less than 0 or is greater than 1.
|
|||
/// </exception>
|
|||
public EntropyCropProcessor(float threshold) |
|||
{ |
|||
Guard.MustBeBetweenOrEqualTo(threshold, 0, 1, nameof(threshold)); |
|||
this.Value = threshold; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the threshold value.
|
|||
/// </summary>
|
|||
public float Value { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void Apply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
ImageBase<TColor, TPacked> temp = new Image<TColor, TPacked>(source.Width, source.Height); |
|||
temp.ClonePixels(source.Width, source.Height, source.Pixels); |
|||
|
|||
// Detect the edges.
|
|||
new SobelProcessor<TColor, TPacked>().Apply(temp, sourceRectangle); |
|||
|
|||
// Apply threshold binarization filter.
|
|||
new BinaryThresholdProcessor<TColor, TPacked>(this.Value).Apply(temp, sourceRectangle); |
|||
|
|||
// Search for the first white pixels
|
|||
Rectangle rectangle = ImageMaths.GetFilteredBoundingRectangle(temp, 0); |
|||
|
|||
if (rectangle == sourceRectangle) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
new CropProcessor<TColor, TPacked>(rectangle).Apply(source, sourceRectangle); |
|||
} |
|||
} |
|||
} |
|||
@ -1,55 +0,0 @@ |
|||
// <copyright file="Pixelate.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
|
|||
using Processors; |
|||
|
|||
/// <summary>
|
|||
/// Extension methods for the <see cref="Image{TColor, TPacked}"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Pixelates an image with the given pixel size.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="size">The size of the pixels.</param>
|
|||
/// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns>
|
|||
public static Image<TColor, TPacked> Pixelate<TColor, TPacked>(this Image<TColor, TPacked> source, int size = 4) |
|||
where TColor : struct, IPackedPixel<TPacked> |
|||
where TPacked : struct |
|||
{ |
|||
return Pixelate(source, size, source.Bounds); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Pixelates an image with the given pixel size.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="size">The size of the pixels.</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{TColor, TPacked}"/>.</returns>
|
|||
public static Image<TColor, TPacked> Pixelate<TColor, TPacked>(this Image<TColor, TPacked> source, int size, Rectangle rectangle) |
|||
where TColor : struct, IPackedPixel<TPacked> |
|||
where TPacked : struct |
|||
{ |
|||
if (size <= 0 || size > source.Height || size > source.Width) |
|||
{ |
|||
throw new ArgumentOutOfRangeException(nameof(size)); |
|||
} |
|||
|
|||
return source.Process(rectangle, new PixelateProcesso<TColor, TPacked>(size)); |
|||
} |
|||
} |
|||
} |
|||
@ -1,58 +0,0 @@ |
|||
// <copyright file="IImageSamplingProcessor.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Processors |
|||
{ |
|||
/// <summary>
|
|||
/// Encapsulates methods to alter the pixels of an image. The processor creates a copy of the original image to operate on.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|||
public interface IImageSamplingProcessor<TColor, TPacked> : IImageProcessor |
|||
where TColor : struct, IPackedPixel<TPacked> |
|||
where TPacked : struct |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the process to the specified portion of the specified <see cref="ImageBase{T, TP}"/>.
|
|||
/// </summary>
|
|||
/// <param name="target">Target image to apply the process to.</param>
|
|||
/// <param name="source">The source image. Cannot be null.</param>
|
|||
/// <param name="sourceRectangle">
|
|||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
|
|||
/// </param>
|
|||
/// <remarks>
|
|||
/// The method keeps the source image unchanged and returns the
|
|||
/// the result of image processing filter as new image.
|
|||
/// </remarks>
|
|||
/// <exception cref="System.ArgumentNullException">
|
|||
/// <paramref name="target"/> is null or <paramref name="source"/> is null.
|
|||
/// </exception>
|
|||
/// <exception cref="System.ArgumentException">
|
|||
/// <paramref name="sourceRectangle"/> doesnt fit the dimension of the image.
|
|||
/// </exception>
|
|||
void Apply(ImageBase<TColor, TPacked> target, ImageBase<TColor, TPacked> source, Rectangle sourceRectangle); |
|||
|
|||
/// <summary>
|
|||
/// Applies the process to the specified portion of the specified <see cref="ImageBase{T, TP}"/> at the specified
|
|||
/// location and with the specified size.
|
|||
/// </summary>
|
|||
/// <param name="target">Target image to apply the process to.</param>
|
|||
/// <param name="source">The source image. Cannot be null.</param>
|
|||
/// <param name="width">The target width.</param>
|
|||
/// <param name="height">The target height.</param>
|
|||
/// <param name="targetRectangle">
|
|||
/// The <see cref="Rectangle"/> structure that specifies the location and size of the drawn image.
|
|||
/// The image is scaled to fit the rectangle.
|
|||
/// </param>
|
|||
/// <param name="sourceRectangle">
|
|||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
|
|||
/// </param>
|
|||
/// <remarks>
|
|||
/// The method keeps the source image unchanged and returns the
|
|||
/// the result of image process as new image.
|
|||
/// </remarks>
|
|||
void Apply(ImageBase<TColor, TPacked> target, ImageBase<TColor, TPacked> source, int width, int height, Rectangle targetRectangle, Rectangle sourceRectangle); |
|||
} |
|||
} |
|||
@ -1,119 +0,0 @@ |
|||
// <copyright file="ImageSamplingProcessor.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Processors |
|||
{ |
|||
using System; |
|||
|
|||
/// <summary>
|
|||
/// Encapsulates methods to alter the pixels of an image. The processor creates a copy of the original image to operate on.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|||
public abstract class ImageSamplingProcessor<TColor, TPacked> : ImageProcessor<TColor, TPacked>, IImageSamplingProcessor<TColor, TPacked> |
|||
where TColor : struct, IPackedPixel<TPacked> |
|||
where TPacked : struct |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public void Apply(ImageBase<TColor, TPacked> target, ImageBase<TColor, TPacked> source, Rectangle sourceRectangle) |
|||
{ |
|||
try |
|||
{ |
|||
this.OnApply(target, source, target.Bounds, sourceRectangle); |
|||
|
|||
this.Apply(target, source, target.Bounds, sourceRectangle, sourceRectangle.Y, sourceRectangle.Bottom); |
|||
|
|||
this.AfterApply(target, source, target.Bounds, sourceRectangle); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. See the inner exception for more detail.", ex); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void Apply(ImageBase<TColor, TPacked> target, ImageBase<TColor, TPacked> source, int width, int height, Rectangle targetRectangle = default(Rectangle), Rectangle sourceRectangle = default(Rectangle)) |
|||
{ |
|||
try |
|||
{ |
|||
TColor[] pixels = new TColor[width * height]; |
|||
target.SetPixels(width, height, pixels); |
|||
|
|||
// Ensure we always have bounds.
|
|||
if (sourceRectangle == Rectangle.Empty) |
|||
{ |
|||
sourceRectangle = source.Bounds; |
|||
} |
|||
|
|||
if (targetRectangle == Rectangle.Empty) |
|||
{ |
|||
targetRectangle = target.Bounds; |
|||
} |
|||
|
|||
this.OnApply(target, source, targetRectangle, sourceRectangle); |
|||
|
|||
this.Apply(target, source, targetRectangle, sourceRectangle, targetRectangle.Y, targetRectangle.Bottom); |
|||
|
|||
this.AfterApply(target, source, target.Bounds, sourceRectangle); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. See the inner exception for more detail.", ex); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the process to the specified portion of the specified <see cref="ImageBase{TColor, TPacked}"/> at the specified location
|
|||
/// and with the specified size.
|
|||
/// </summary>
|
|||
/// <param name="target">Target image to apply the process to.</param>
|
|||
/// <param name="source">The source image. Cannot be null.</param>
|
|||
/// <param name="targetRectangle">
|
|||
/// The <see cref="Rectangle"/> structure that specifies the location and size of the drawn image.
|
|||
/// The image is scaled to fit the rectangle.
|
|||
/// </param>
|
|||
/// <param name="sourceRectangle">
|
|||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
|
|||
/// </param>
|
|||
/// <param name="startY">The index of the row within the source image to start processing.</param>
|
|||
/// <param name="endY">The index of the row within the source image to end processing.</param>
|
|||
/// <remarks>
|
|||
/// The method keeps the source image unchanged and returns the the result of image process as new image.
|
|||
/// </remarks>
|
|||
public abstract void Apply(ImageBase<TColor, TPacked> target, ImageBase<TColor, TPacked> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY); |
|||
|
|||
/// <summary>
|
|||
/// This method is called before the process is applied to prepare the processor.
|
|||
/// </summary>
|
|||
/// <param name="target">Target image to apply the process to.</param>
|
|||
/// <param name="source">The source image. Cannot be null.</param>
|
|||
/// <param name="targetRectangle">
|
|||
/// The <see cref="Rectangle"/> structure that specifies the location and size of the drawn image.
|
|||
/// The image is scaled to fit the rectangle.
|
|||
/// </param>
|
|||
/// <param name="sourceRectangle">
|
|||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
|
|||
/// </param>
|
|||
protected virtual void OnApply(ImageBase<TColor, TPacked> target, ImageBase<TColor, TPacked> source, Rectangle targetRectangle, Rectangle sourceRectangle) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// This method is called after the process is applied to prepare the processor.
|
|||
/// </summary>
|
|||
/// <param name="target">Target image to apply the process to.</param>
|
|||
/// <param name="source">The source image. Cannot be null.</param>
|
|||
/// <param name="targetRectangle">
|
|||
/// The <see cref="Rectangle"/> structure that specifies the location and size of the drawn image.
|
|||
/// The image is scaled to fit the rectangle.
|
|||
/// </param>
|
|||
/// <param name="sourceRectangle">
|
|||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
|
|||
/// </param>
|
|||
protected virtual void AfterApply(ImageBase<TColor, TPacked> target, ImageBase<TColor, TPacked> source, Rectangle targetRectangle, Rectangle sourceRectangle) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,49 +0,0 @@ |
|||
// <copyright file="CropProcessor.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Processors |
|||
{ |
|||
using System.Threading.Tasks; |
|||
|
|||
/// <summary>
|
|||
/// Provides methods to allow the cropping of an image.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|||
public class CropProcessor<TColor, TPacked> : ImageSamplingProcessor<TColor, TPacked> |
|||
where TColor : struct, IPackedPixel<TPacked> |
|||
where TPacked : struct |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public override void Apply(ImageBase<TColor, TPacked> target, ImageBase<TColor, TPacked> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
int startX = targetRectangle.X; |
|||
int endX = targetRectangle.Right; |
|||
int sourceX = sourceRectangle.X; |
|||
int sourceY = sourceRectangle.Y; |
|||
|
|||
Guard.MustBeGreaterThanOrEqualTo(startX, sourceX, nameof(targetRectangle)); |
|||
Guard.MustBeGreaterThanOrEqualTo(startY, sourceY, nameof(targetRectangle)); |
|||
Guard.MustBeLessThanOrEqualTo(endX, sourceRectangle.Right, nameof(targetRectangle)); |
|||
Guard.MustBeLessThanOrEqualTo(endY, sourceRectangle.Bottom, nameof(targetRectangle)); |
|||
|
|||
using (PixelAccessor<TColor, TPacked> sourcePixels = source.Lock()) |
|||
using (PixelAccessor<TColor, TPacked> targetPixels = target.Lock()) |
|||
{ |
|||
Parallel.For( |
|||
startY, |
|||
endY, |
|||
this.ParallelOptions, |
|||
y => |
|||
{ |
|||
for (int x = startX; x < endX; x++) |
|||
{ |
|||
targetPixels[x, y] = sourcePixels[x + sourceX, y + sourceY]; |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,107 +0,0 @@ |
|||
// <copyright file="EntropyCropProcessor.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Processors |
|||
{ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
|
|||
/// <summary>
|
|||
/// Provides methods to allow the cropping of an image to preserve areas of highest
|
|||
/// entropy.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|||
public class EntropyCropProcessor<TColor, TPacked> : ImageSamplingProcessor<TColor, TPacked> |
|||
where TColor : struct, IPackedPixel<TPacked> |
|||
where TPacked : struct |
|||
{ |
|||
/// <summary>
|
|||
/// The rectangle for cropping
|
|||
/// </summary>
|
|||
private Rectangle cropRectangle; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="EntropyCropProcessor{TColor, TPacked}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="threshold">The threshold to split the image. Must be between 0 and 1.</param>
|
|||
/// <exception cref="System.ArgumentException">
|
|||
/// <paramref name="threshold"/> is less than 0 or is greater than 1.
|
|||
/// </exception>
|
|||
public EntropyCropProcessor(float threshold) |
|||
{ |
|||
Guard.MustBeBetweenOrEqualTo(threshold, 0, 1, nameof(threshold)); |
|||
this.Value = threshold; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the threshold value.
|
|||
/// </summary>
|
|||
public float Value { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
public override void Apply(ImageBase<TColor, TPacked> target, ImageBase<TColor, TPacked> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
// Jump out, we'll deal with that later.
|
|||
if (source.Bounds == target.Bounds) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
int targetY = this.cropRectangle.Y; |
|||
int targetBottom = this.cropRectangle.Bottom; |
|||
int startX = this.cropRectangle.X; |
|||
int endX = this.cropRectangle.Right; |
|||
|
|||
int minY = Math.Max(targetY, startY); |
|||
int maxY = Math.Min(targetBottom, endY); |
|||
|
|||
using (PixelAccessor<TColor, TPacked> sourcePixels = source.Lock()) |
|||
using (PixelAccessor<TColor, TPacked> targetPixels = target.Lock()) |
|||
{ |
|||
Parallel.For( |
|||
minY, |
|||
maxY, |
|||
this.ParallelOptions, |
|||
y => |
|||
{ |
|||
for (int x = startX; x < endX; x++) |
|||
{ |
|||
targetPixels[x - startX, y - targetY] = sourcePixels[x, y]; |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnApply(ImageBase<TColor, TPacked> target, ImageBase<TColor, TPacked> source, Rectangle targetRectangle, Rectangle sourceRectangle) |
|||
{ |
|||
ImageBase<TColor, TPacked> temp = new Image<TColor, TPacked>(source.Width, source.Height); |
|||
|
|||
// Detect the edges.
|
|||
new SobelProcessor<TColor, TPacked>().Apply(temp, source, sourceRectangle); |
|||
|
|||
// Apply threshold binarization filter.
|
|||
new BinaryThresholdProcessor<TColor, TPacked>(.5f).Apply(temp, sourceRectangle); |
|||
|
|||
// Search for the first white pixels
|
|||
Rectangle rectangle = ImageMaths.GetFilteredBoundingRectangle(temp, 0); |
|||
|
|||
// Reset the target pixel to the correct size.
|
|||
target.SetPixels(rectangle.Width, rectangle.Height, new TColor[rectangle.Width * rectangle.Height]); |
|||
this.cropRectangle = rectangle; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void AfterApply(ImageBase<TColor, TPacked> target, ImageBase<TColor, TPacked> source, Rectangle targetRectangle, Rectangle sourceRectangle) |
|||
{ |
|||
// Copy the pixels over.
|
|||
if (source.Bounds == target.Bounds) |
|||
{ |
|||
target.ClonePixels(target.Width, target.Height, source.Pixels); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,60 +0,0 @@ |
|||
// <copyright file="OilPaintTest.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Tests |
|||
{ |
|||
using System; |
|||
using System.IO; |
|||
|
|||
using Xunit; |
|||
|
|||
public class OilPaintTest : FileTestBase |
|||
{ |
|||
public static readonly TheoryData<Tuple<int, int>> OilPaintValues |
|||
= new TheoryData<Tuple<int, int>> |
|||
{ |
|||
new Tuple<int, int>(15,10), |
|||
new Tuple<int, int>(6,5) |
|||
}; |
|||
|
|||
[Theory] |
|||
[MemberData(nameof(OilPaintValues))] |
|||
public void ImageShouldApplyOilPaintFilter(Tuple<int, int> value) |
|||
{ |
|||
string path = CreateOutputDirectory("OilPaint"); |
|||
|
|||
foreach (TestFile file in Files) |
|||
{ |
|||
string filename = file.GetFileName(value); |
|||
Image image = file.CreateImage(); |
|||
|
|||
using (FileStream output = File.OpenWrite($"{path}/{filename}")) |
|||
{ |
|||
image.OilPaint(value.Item1, value.Item2) |
|||
.Save(output); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Theory] |
|||
[MemberData(nameof(OilPaintValues))] |
|||
public void ImageShouldApplyOilPaintFilterInBox(Tuple<int, int> value) |
|||
{ |
|||
string path = CreateOutputDirectory("OilPaint"); |
|||
|
|||
foreach (TestFile file in Files) |
|||
{ |
|||
string filename = file.GetFileName(value + "-InBox"); |
|||
Image image = file.CreateImage(); |
|||
|
|||
using (FileStream output = File.OpenWrite($"{path}/{filename}")) |
|||
{ |
|||
image.OilPaint(value.Item1, value.Item2, new Rectangle(10, 10, image.Width / 2, image.Height / 2)) |
|||
.Save(output); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,59 +0,0 @@ |
|||
// <copyright file="PixelateTest.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Tests |
|||
{ |
|||
using System.IO; |
|||
|
|||
using Xunit; |
|||
|
|||
public class PixelateTest : FileTestBase |
|||
{ |
|||
public static readonly TheoryData<int> PixelateValues |
|||
= new TheoryData<int> |
|||
{ |
|||
4 , |
|||
8 |
|||
}; |
|||
|
|||
[Theory] |
|||
[MemberData(nameof(PixelateValues))] |
|||
public void ImageShouldApplyPixelateFilter(int value) |
|||
{ |
|||
string path = CreateOutputDirectory("Pixelate"); |
|||
|
|||
foreach (TestFile file in Files) |
|||
{ |
|||
string filename = file.GetFileName(value); |
|||
Image image = file.CreateImage(); |
|||
|
|||
using (FileStream output = File.OpenWrite($"{path}/{filename}")) |
|||
{ |
|||
image.Pixelate(value) |
|||
.Save(output); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Theory] |
|||
[MemberData(nameof(PixelateValues))] |
|||
public void ImageShouldApplyPixelateFilterInBox(int value) |
|||
{ |
|||
string path = CreateOutputDirectory("Pixelate"); |
|||
|
|||
foreach (TestFile file in Files) |
|||
{ |
|||
string filename = file.GetFileName(value + "-InBox"); |
|||
Image image = file.CreateImage(); |
|||
|
|||
using (FileStream output = File.OpenWrite($"{path}/{filename}")) |
|||
{ |
|||
image.Pixelate(value, new Rectangle(10, 10, image.Width / 2, image.Height / 2)) |
|||
.Save(output); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue