diff --git a/README.md b/README.md
index 89f703cbc..0b5ff1d26 100644
--- a/README.md
+++ b/README.md
@@ -48,7 +48,7 @@ Honestly... I don't know. I could be writing code that may be suddenly obsolete.
- [x] Triangle
- [x] Welch
- Cropping
- - [ ] Rectangular Crop
+ - [x] Rectangular Crop
- [ ] Elliptical Crop
- [ ] Entropy Crop
- Rotation
diff --git a/src/ImageProcessor/Filters/Convolution/GuassianBlur.cs b/src/ImageProcessor/Filters/Convolution/GuassianBlur.cs
index 0532e7b7f..0973b1a61 100644
--- a/src/ImageProcessor/Filters/Convolution/GuassianBlur.cs
+++ b/src/ImageProcessor/Filters/Convolution/GuassianBlur.cs
@@ -44,6 +44,34 @@ namespace ImageProcessor.Filters
this.sigma = sigma;
}
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The 'radius' value representing the size of the area to sample.
+ ///
+ public GuassianBlur(int radius)
+ {
+ this.kernelSize = (radius * 2) + 1;
+ this.sigma = radius;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The 'sigma' value representing the weight of the blur.
+ ///
+ ///
+ /// The 'radius' value representing the size of the area to sample.
+ /// This should be at least twice the sigma value.
+ ///
+ public GuassianBlur(float sigma, int radius)
+ {
+ this.kernelSize = (radius * 2) + 1;
+ this.sigma = sigma;
+ }
+
///
public override float[,] KernelX => this.kernelX;
diff --git a/src/ImageProcessor/ImageExtensions.cs b/src/ImageProcessor/ImageExtensions.cs
index 2b341d766..6c52fe15e 100644
--- a/src/ImageProcessor/ImageExtensions.cs
+++ b/src/ImageProcessor/ImageExtensions.cs
@@ -1,4 +1,4 @@
-//
+//
// Copyright (c) James South and contributors.
// Licensed under the Apache License, Version 2.0.
//
@@ -62,6 +62,7 @@ namespace ImageProcessor
///
/// Applies the collection of processors to the image.
+ /// This method does not resize the target image.
///
/// The image this method extends.
///
@@ -95,6 +96,10 @@ namespace ImageProcessor
///
/// Applies the collection of processors to the image.
+ ///
+ /// This method does will resize the target image if the source and target
+ /// rectangles are different.
+ ///
///
/// The source image. Cannot be null.
/// The target image width.
diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj
index 8e9ef8c0a..9ce6dc4bd 100644
--- a/src/ImageProcessor/ImageProcessor.csproj
+++ b/src/ImageProcessor/ImageProcessor.csproj
@@ -235,6 +235,7 @@
+
diff --git a/src/ImageProcessor/Samplers/Crop.cs b/src/ImageProcessor/Samplers/Crop.cs
new file mode 100644
index 000000000..7ed0bb2df
--- /dev/null
+++ b/src/ImageProcessor/Samplers/Crop.cs
@@ -0,0 +1,44 @@
+//
+// Copyright (c) James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Samplers
+{
+ using System.Threading.Tasks;
+
+ ///
+ /// Provides methods to allow the cropping of an image.
+ ///
+ public class Crop : ParallelImageProcessor
+ {
+ ///
+ protected override void Apply(
+ ImageBase target,
+ ImageBase source,
+ Rectangle targetRectangle,
+ Rectangle sourceRectangle,
+ int startY,
+ int endY)
+ {
+ int targetY = targetRectangle.Y;
+ int targetBottom = targetRectangle.Bottom;
+ int startX = targetRectangle.X;
+ int endX = targetRectangle.Right;
+
+ Parallel.For(
+ startY,
+ endY,
+ y =>
+ {
+ if (y >= targetY && y < targetBottom)
+ {
+ for (int x = startX; x < endX; x++)
+ {
+ target[x, y] = source[x, y];
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/src/ImageProcessor/Samplers/ImageSampleExtensions.cs b/src/ImageProcessor/Samplers/ImageSampleExtensions.cs
index b560e4779..6b2c0bacf 100644
--- a/src/ImageProcessor/Samplers/ImageSampleExtensions.cs
+++ b/src/ImageProcessor/Samplers/ImageSampleExtensions.cs
@@ -36,7 +36,8 @@ namespace ImageProcessor.Samplers
}
///
- /// Resizes an image to the given width and height with the given sampler.
+ /// Resizes an image to the given width and height with the given sampler,
+ /// source rectangle, and target rectangle.
///
/// The image to resize.
/// The target image width.
@@ -54,5 +55,48 @@ namespace ImageProcessor.Samplers
{
return source.Process(width, height, sourceRectangle, targetRectangle, new Resize(sampler));
}
+
+ ///
+ /// Crops an image to the given width and height.
+ ///
+ /// The image to resize.
+ /// The target image width.
+ /// The target image height.
+ /// The
+ public static Image Crop(this Image source, int width, int height)
+ {
+ return Crop(source, width, height, source.Bounds, new Rectangle(0, 0, width, height));
+ }
+
+ ///
+ /// Crops an image to the given width and height with the given source rectangle,
+ /// and target rectangle.
+ ///
+ /// If the source rectangle is smaller than the target dimensions then the
+ /// area within the source is resized performing a zoomed crop.
+ ///
+ ///
+ /// The image to resize.
+ /// The target image width.
+ /// The target image height.
+ ///
+ /// The structure that specifies the portion of the image object to draw.
+ ///
+ ///
+ /// The structure that specifies the location and size of the drawn image.
+ /// The image is cropped to fit the rectangle.
+ ///
+ /// The
+ public static Image Crop(this Image source, int width, int height, Rectangle sourceRectangle, Rectangle targetRectangle)
+ {
+ if (sourceRectangle.Width < targetRectangle.Width || sourceRectangle.Height < targetRectangle.Height)
+ {
+ // If the source rectangle is smaller than the target perform a
+ // cropped zoom.
+ source = source.Resize(sourceRectangle.Width, sourceRectangle.Height);
+ }
+
+ return source.Process(width, height, sourceRectangle, targetRectangle, new Crop());
+ }
}
}
diff --git a/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs b/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs
index 1e71cf112..a507c5a50 100644
--- a/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs
+++ b/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs
@@ -1,7 +1,6 @@
namespace ImageProcessor.Tests
{
- using System;
using System.Diagnostics;
using System.IO;
@@ -47,7 +46,6 @@ namespace ImageProcessor.Tests
string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file);
using (FileStream output = File.OpenWrite($"Resized/{filename}"))
{
- //image.Resize(image.Width / 2, image.Height / 2, sampler).Save(output);
image.Resize(image.Width / 2, image.Height / 2, sampler).Save(output);
}
@@ -56,6 +54,28 @@ namespace ImageProcessor.Tests
}
}
+ [Fact]
+ public void ImageShouldCrop()
+ {
+ if (!Directory.Exists("Cropped"))
+ {
+ Directory.CreateDirectory("Cropped");
+ }
+
+ foreach (string file in Files)
+ {
+ using (FileStream stream = File.OpenRead(file))
+ {
+ Image image = new Image(stream);
+ string filename = Path.GetFileNameWithoutExtension(file) + "-Cropped" + Path.GetExtension(file);
+ using (FileStream output = File.OpenWrite($"Cropped/{filename}"))
+ {
+ image.Crop(image.Width / 2, image.Height / 2).Save(output);
+ }
+ }
+ }
+ }
+
[Theory]
[InlineData(-2, 0)]
[InlineData(-1, 0)]