Browse Source

Complete progress messaging.

Former-commit-id: 6a4ad9c1dc9ae7635bb4108e2840bcf88c4894e5
Former-commit-id: 5fe2186a4fbc536b4d050ac4a5b2649b8532fe21
Former-commit-id: 691721d5d4d6e3aa1d18deb7b2da7b521f497bff
pull/17/head
James Jackson-South 10 years ago
parent
commit
06d5ce7e64
  1. 384
      src/ImageProcessor/Filters/ImageFilterExtensions.cs
  2. 12
      src/ImageProcessor/IImageProcessor.cs
  3. 38
      src/ImageProcessor/ParallelImageProcessor.cs
  4. 23
      src/ImageProcessor/ProgressEventArgs.cs
  5. 15
      src/ImageProcessor/Samplers/ImageSampleExtensions.cs
  6. 6
      tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs
  7. 16
      tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs

384
src/ImageProcessor/Filters/ImageFilterExtensions.cs

@ -15,10 +15,11 @@ namespace ImageProcessor.Filters
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="percent">The new opacity of the image. Must be between 0 and 100.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Alpha(this Image source, int percent)
public static Image Alpha(this Image source, int percent, ProgressEventHandler progressHandler = null)
{
return Alpha(source, percent, source.Bounds);
return Alpha(source, percent, source.Bounds, progressHandler);
}
/// <summary>
@ -29,10 +30,21 @@ namespace ImageProcessor.Filters
/// <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"/>.</returns>
public static Image Alpha(this Image source, int percent, Rectangle rectangle)
public static Image Alpha(this Image source, int percent, Rectangle rectangle, ProgressEventHandler progressHandler = null)
{
return source.Process(rectangle, new Alpha(percent));
Alpha processor = new Alpha(percent);
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
/// <summary>
@ -40,10 +52,21 @@ namespace ImageProcessor.Filters
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color to set as the background.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image BackgroundColor(this Image source, Color color)
public static Image BackgroundColor(this Image source, Color color, ProgressEventHandler progressHandler = null)
{
return source.Process(source.Bounds, new BackgroundColor(color));
BackgroundColor processor = new BackgroundColor(color);
processor.OnProgress += progressHandler;
try
{
return source.Process(source.Bounds, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
/// <summary>
@ -52,10 +75,11 @@ namespace ImageProcessor.Filters
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="percent">The opacity of the image image to blend. Must be between 0 and 100.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Blend(this Image source, ImageBase image, int percent = 50)
public static Image Blend(this Image source, ImageBase image, int percent = 50, ProgressEventHandler progressHandler = null)
{
return source.Process(source.Bounds, new Blend(image, percent));
return Blend(source, image, percent, source.Bounds, progressHandler);
}
/// <summary>
@ -67,20 +91,32 @@ namespace ImageProcessor.Filters
/// <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"/>.</returns>
public static Image Blend(this Image source, ImageBase image, int percent, Rectangle rectangle)
public static Image Blend(this Image source, ImageBase image, int percent, Rectangle rectangle, ProgressEventHandler progressHandler = null)
{
return source.Process(rectangle, new Blend(image, percent));
Blend processor = new Blend(image, percent);
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
/// <summary>
/// Applies black and white toning to the image.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image BlackWhite(this Image source)
public static Image BlackWhite(this Image source, ProgressEventHandler progressHandler = null)
{
return BlackWhite(source, source.Bounds);
return BlackWhite(source, source.Bounds, progressHandler);
}
/// <summary>
@ -90,10 +126,21 @@ namespace ImageProcessor.Filters
/// <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"/>.</returns>
public static Image BlackWhite(this Image source, Rectangle rectangle)
public static Image BlackWhite(this Image source, Rectangle rectangle, ProgressEventHandler progressHandler = null)
{
return source.Process(rectangle, new BlackWhite());
BlackWhite processor = new BlackWhite();
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
/// <summary>
@ -101,10 +148,11 @@ namespace ImageProcessor.Filters
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="radius">The 'radius' value representing the size of the area to sample.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image BoxBlur(this Image source, int radius = 7)
public static Image BoxBlur(this Image source, int radius = 7, ProgressEventHandler progressHandler = null)
{
return BoxBlur(source, radius, source.Bounds);
return BoxBlur(source, radius, source.Bounds, progressHandler);
}
/// <summary>
@ -115,10 +163,21 @@ namespace ImageProcessor.Filters
/// <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"/>.</returns>
public static Image BoxBlur(this Image source, int radius, Rectangle rectangle)
public static Image BoxBlur(this Image source, int radius, Rectangle rectangle, ProgressEventHandler progressHandler = null)
{
return source.Process(rectangle, new BoxBlur(radius));
BoxBlur processor = new BoxBlur(radius);
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
/// <summary>
@ -126,10 +185,11 @@ namespace ImageProcessor.Filters
/// </summary>
/// <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"/>.</returns>
public static Image Brightness(this Image source, int amount)
public static Image Brightness(this Image source, int amount, ProgressEventHandler progressHandler = null)
{
return Brightness(source, amount, source.Bounds);
return Brightness(source, amount, source.Bounds, progressHandler);
}
/// <summary>
@ -140,10 +200,21 @@ namespace ImageProcessor.Filters
/// <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"/>.</returns>
public static Image Brightness(this Image source, int amount, Rectangle rectangle)
public static Image Brightness(this Image source, int amount, Rectangle rectangle, ProgressEventHandler progressHandler = null)
{
return source.Process(rectangle, new Brightness(amount));
Brightness processor = new Brightness(amount);
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
/// <summary>
@ -151,10 +222,11 @@ namespace ImageProcessor.Filters
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="amount">The new contrast 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"/>.</returns>
public static Image Contrast(this Image source, int amount)
public static Image Contrast(this Image source, int amount, ProgressEventHandler progressHandler = null)
{
return Contrast(source, amount, source.Bounds);
return Contrast(source, amount, source.Bounds, progressHandler);
}
/// <summary>
@ -165,10 +237,21 @@ namespace ImageProcessor.Filters
/// <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"/>.</returns>
public static Image Contrast(this Image source, int amount, Rectangle rectangle)
public static Image Contrast(this Image source, int amount, Rectangle rectangle, ProgressEventHandler progressHandler = null)
{
return source.Process(rectangle, new Contrast(amount));
Contrast processor = new Contrast(amount);
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
/// <summary>
@ -176,10 +259,11 @@ namespace ImageProcessor.Filters
/// operating in greyscale mode.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image DetectEdges(this Image source)
public static Image DetectEdges(this Image source, ProgressEventHandler progressHandler = null)
{
return DetectEdges(source, source.Bounds, new Sobel { Greyscale = true });
return DetectEdges(source, source.Bounds, new Sobel { Greyscale = true }, progressHandler);
}
/// <summary>
@ -187,10 +271,11 @@ namespace ImageProcessor.Filters
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="filter">The filter for detecting edges.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image DetectEdges(this Image source, IEdgeDetectorFilter filter)
public static Image DetectEdges(this Image source, IEdgeDetectorFilter filter, ProgressEventHandler progressHandler = null)
{
return DetectEdges(source, source.Bounds, filter);
return DetectEdges(source, source.Bounds, filter, progressHandler);
}
/// <summary>
@ -201,10 +286,20 @@ namespace ImageProcessor.Filters
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <param name="filter">The filter for detecting edges.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image DetectEdges(this Image source, Rectangle rectangle, IEdgeDetectorFilter filter)
public static Image DetectEdges(this Image source, Rectangle rectangle, IEdgeDetectorFilter filter, ProgressEventHandler progressHandler = null)
{
return source.Process(rectangle, filter);
filter.OnProgress += progressHandler;
try
{
return source.Process(rectangle, filter);
}
finally
{
filter.OnProgress -= progressHandler;
}
}
/// <summary>
@ -212,10 +307,11 @@ namespace ImageProcessor.Filters
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="mode">The formula to apply to perform the operation.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Greyscale(this Image source, GreyscaleMode mode = GreyscaleMode.Bt709)
public static Image Greyscale(this Image source, GreyscaleMode mode = GreyscaleMode.Bt709, ProgressEventHandler progressHandler = null)
{
return Greyscale(source, source.Bounds, mode);
return Greyscale(source, source.Bounds, mode, progressHandler);
}
/// <summary>
@ -226,12 +322,24 @@ namespace ImageProcessor.Filters
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <param name="mode">The formula to apply to perform the operation.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Greyscale(this Image source, Rectangle rectangle, GreyscaleMode mode = GreyscaleMode.Bt709)
public static Image Greyscale(this Image source, Rectangle rectangle, GreyscaleMode mode = GreyscaleMode.Bt709, ProgressEventHandler progressHandler = null)
{
return mode == GreyscaleMode.Bt709
? source.Process(rectangle, new GreyscaleBt709())
: source.Process(rectangle, new GreyscaleBt601());
IImageProcessor processor = mode == GreyscaleMode.Bt709
? (IImageProcessor)new GreyscaleBt709()
: new GreyscaleBt601();
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
/// <summary>
@ -239,10 +347,11 @@ namespace ImageProcessor.Filters
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="sigma">The 'sigma' value representing the weight of the blur.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image GuassianBlur(this Image source, float sigma = 3f)
public static Image GuassianBlur(this Image source, float sigma = 3f, ProgressEventHandler progressHandler = null)
{
return GuassianBlur(source, sigma, source.Bounds);
return GuassianBlur(source, sigma, source.Bounds, progressHandler);
}
/// <summary>
@ -253,10 +362,21 @@ namespace ImageProcessor.Filters
/// <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"/>.</returns>
public static Image GuassianBlur(this Image source, float sigma, Rectangle rectangle)
public static Image GuassianBlur(this Image source, float sigma, Rectangle rectangle, ProgressEventHandler progressHandler = null)
{
return source.Process(rectangle, new GuassianBlur(sigma));
GuassianBlur processor = new GuassianBlur(sigma);
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
/// <summary>
@ -264,10 +384,11 @@ namespace ImageProcessor.Filters
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="sigma">The 'sigma' value representing the weight of the blur.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image GuassianSharpen(this Image source, float sigma = 3f)
public static Image GuassianSharpen(this Image source, float sigma = 3f, ProgressEventHandler progressHandler = null)
{
return GuassianSharpen(source, sigma, source.Bounds);
return GuassianSharpen(source, sigma, source.Bounds, progressHandler);
}
/// <summary>
@ -278,10 +399,21 @@ namespace ImageProcessor.Filters
/// <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"/>.</returns>
public static Image GuassianSharpen(this Image source, float sigma, Rectangle rectangle)
public static Image GuassianSharpen(this Image source, float sigma, Rectangle rectangle, ProgressEventHandler progressHandler = null)
{
return source.Process(rectangle, new GuassianSharpen(sigma));
GuassianSharpen processor = new GuassianSharpen(sigma);
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
/// <summary>
@ -289,10 +421,11 @@ namespace ImageProcessor.Filters
/// </summary>
/// <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"/>.</returns>
public static Image Hue(this Image source, float degrees)
public static Image Hue(this Image source, float degrees, ProgressEventHandler progressHandler = null)
{
return Hue(source, degrees, source.Bounds);
return Hue(source, degrees, source.Bounds, progressHandler);
}
/// <summary>
@ -303,20 +436,32 @@ namespace ImageProcessor.Filters
/// <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"/>.</returns>
public static Image Hue(this Image source, float degrees, Rectangle rectangle)
public static Image Hue(this Image source, float degrees, Rectangle rectangle, ProgressEventHandler progressHandler = null)
{
return source.Process(rectangle, new Hue(degrees));
Hue processor = new Hue(degrees);
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
/// <summary>
/// Inverts the colors of the image.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Invert(this Image source)
public static Image Invert(this Image source, ProgressEventHandler progressHandler = null)
{
return Invert(source, source.Bounds);
return Invert(source, source.Bounds, progressHandler);
}
/// <summary>
@ -326,20 +471,32 @@ namespace ImageProcessor.Filters
/// <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"/>.</returns>
public static Image Invert(this Image source, Rectangle rectangle)
public static Image Invert(this Image source, Rectangle rectangle, ProgressEventHandler progressHandler = null)
{
return source.Process(rectangle, new Invert());
Invert processor = new Invert();
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
/// <summary>
/// Alters the colors of the image recreating an old Kodachrome camera effect.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Kodachrome(this Image source)
public static Image Kodachrome(this Image source, ProgressEventHandler progressHandler = null)
{
return Kodachrome(source, source.Bounds);
return Kodachrome(source, source.Bounds, progressHandler);
}
/// <summary>
@ -349,20 +506,32 @@ namespace ImageProcessor.Filters
/// <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"/>.</returns>
public static Image Kodachrome(this Image source, Rectangle rectangle)
public static Image Kodachrome(this Image source, Rectangle rectangle, ProgressEventHandler progressHandler = null)
{
return source.Process(rectangle, new Kodachrome());
Kodachrome processor = new Kodachrome();
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
/// <summary>
/// Alters the colors of the image recreating an old Lomograph camera effect.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Lomograph(this Image source)
public static Image Lomograph(this Image source, ProgressEventHandler progressHandler = null)
{
return Lomograph(source, source.Bounds);
return Lomograph(source, source.Bounds, progressHandler);
}
/// <summary>
@ -372,20 +541,32 @@ namespace ImageProcessor.Filters
/// <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"/>.</returns>
public static Image Lomograph(this Image source, Rectangle rectangle)
public static Image Lomograph(this Image source, Rectangle rectangle, ProgressEventHandler progressHandler = null)
{
return source.Process(rectangle, new Lomograph());
Lomograph processor = new Lomograph();
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
/// <summary>
/// Alters the colors of the image recreating an old Polaroid camera effect.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Polaroid(this Image source)
public static Image Polaroid(this Image source, ProgressEventHandler progressHandler = null)
{
return Polaroid(source, source.Bounds);
return Polaroid(source, source.Bounds, progressHandler);
}
/// <summary>
@ -395,10 +576,21 @@ namespace ImageProcessor.Filters
/// <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"/>.</returns>
public static Image Polaroid(this Image source, Rectangle rectangle)
public static Image Polaroid(this Image source, Rectangle rectangle, ProgressEventHandler progressHandler = null)
{
return source.Process(rectangle, new Polaroid());
Polaroid processor = new Polaroid();
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
/// <summary>
@ -406,10 +598,11 @@ namespace ImageProcessor.Filters
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="size">The size of the pixels.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Pixelate(this Image source, int size = 4)
public static Image Pixelate(this Image source, int size = 4, ProgressEventHandler progressHandler = null)
{
return source.Process(source.Bounds, new Pixelate(size));
return Pixelate(source, size, source.Bounds, progressHandler);
}
/// <summary>
@ -420,10 +613,21 @@ namespace ImageProcessor.Filters
/// <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"/>.</returns>
public static Image Pixelate(this Image source, int size, Rectangle rectangle)
public static Image Pixelate(this Image source, int size, Rectangle rectangle, ProgressEventHandler progressHandler = null)
{
return source.Process(rectangle, new Pixelate(size));
Pixelate processor = new Pixelate(size);
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
/// <summary>
@ -431,10 +635,11 @@ namespace ImageProcessor.Filters
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="amount">The new saturation 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"/>.</returns>
public static Image Saturation(this Image source, int amount)
public static Image Saturation(this Image source, int amount, ProgressEventHandler progressHandler = null)
{
return Saturation(source, amount, source.Bounds);
return Saturation(source, amount, source.Bounds, progressHandler);
}
/// <summary>
@ -445,20 +650,32 @@ namespace ImageProcessor.Filters
/// <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"/>.</returns>
public static Image Saturation(this Image source, int amount, Rectangle rectangle)
public static Image Saturation(this Image source, int amount, Rectangle rectangle, ProgressEventHandler progressHandler = null)
{
return source.Process(rectangle, new Saturation(amount));
Saturation processor = new Saturation(amount);
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
/// <summary>
/// Applies sepia toning to the image.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Sepia(this Image source)
public static Image Sepia(this Image source, ProgressEventHandler progressHandler = null)
{
return Sepia(source, source.Bounds);
return Sepia(source, source.Bounds, progressHandler);
}
/// <summary>
@ -468,10 +685,21 @@ namespace ImageProcessor.Filters
/// <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"/>.</returns>
public static Image Sepia(this Image source, Rectangle rectangle)
public static Image Sepia(this Image source, Rectangle rectangle, ProgressEventHandler progressHandler = null)
{
return source.Process(rectangle, new Sepia());
Sepia processor = new Sepia();
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
}
}

12
src/ImageProcessor/IImageProcessor.cs

@ -5,17 +5,11 @@
namespace ImageProcessor
{
public class ProgressEventArgs : System.EventArgs
{
public int numRowsProcessed;
public int totalRows;
}
/// <summary>
/// A delegate which is called as progress is made processing the image.
/// A delegate which is called as progress is made processing an image.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <param name="sender">The source of the event.</param>
/// <param name="e">An object that contains the event data.</param>
public delegate void ProgressEventHandler(object sender, ProgressEventArgs e);
/// <summary>

38
src/ImageProcessor/ParallelImageProcessor.cs

@ -32,24 +32,6 @@ namespace ImageProcessor
/// </summary>
private int totalRows;
/// <summary>
/// Must be called by derived classes after processing a single row.
/// </summary>
protected void OnRowProcessed()
{
if(this.OnProgress != null)
{
int currThreadNumRows = Interlocked.Add(ref this.numRowsProcessed, 1);
// Multi-pass filters process multiple times more rows than totalRows, so update totalRows on the fly
if (currThreadNumRows > this.totalRows)
this.totalRows = currThreadNumRows;
// Report progress. This may be on the client's thread, or on a Task library thread.
this.OnProgress(this, new ProgressEventArgs { numRowsProcessed = currThreadNumRows, totalRows = this.totalRows });
}
}
/// <inheritdoc/>
public void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle)
{
@ -191,5 +173,25 @@ namespace ImageProcessor
protected virtual void AfterApply(ImageBase source, ImageBase target, Rectangle targetRectangle, Rectangle sourceRectangle)
{
}
/// <summary>
/// Must be called by derived classes after processing a single row.
/// </summary>
protected void OnRowProcessed()
{
if (this.OnProgress != null)
{
int currThreadNumRows = Interlocked.Add(ref this.numRowsProcessed, 1);
// Multi-pass filters process multiple times more rows than totalRows, so update totalRows on the fly
if (currThreadNumRows > this.totalRows)
{
this.totalRows = currThreadNumRows;
}
// Report progress. This may be on the client's thread, or on a Task library thread.
this.OnProgress(this, new ProgressEventArgs { RowsProcessed = currThreadNumRows, TotalRows = this.totalRows });
}
}
}
}

23
src/ImageProcessor/ProgressEventArgs.cs

@ -0,0 +1,23 @@
// <copyright file="ProgressEventArgs.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessor
{
/// <summary>
/// Contains event data related to the progress made processing an image.
/// </summary>
public class ProgressEventArgs : System.EventArgs
{
/// <summary>
/// Gets or sets the number of rows processed.
/// </summary>
public int RowsProcessed { get; set; }
/// <summary>
/// Gets or sets the total number of rows.
/// </summary>
public int TotalRows { get; set; }
}
}

15
src/ImageProcessor/Samplers/ImageSampleExtensions.cs

@ -47,8 +47,9 @@ namespace ImageProcessor.Samplers
source = source.Resize(sourceRectangle.Width, sourceRectangle.Height);
}
var processor = new Crop();
Crop processor = new Crop();
processor.OnProgress += progressHandler;
try
{
return source.Process(width, height, sourceRectangle, new Rectangle(0, 0, width, height), processor);
@ -68,8 +69,9 @@ namespace ImageProcessor.Samplers
/// <returns>The <see cref="Image"/></returns>
public static Image EntropyCrop(this Image source, float threshold = .5f, ProgressEventHandler progressHandler = null)
{
var processor = new EntropyCrop(threshold);
EntropyCrop processor = new EntropyCrop(threshold);
processor.OnProgress += progressHandler;
try
{
return source.Process(source.Width, source.Height, source.Bounds, source.Bounds, processor);
@ -135,8 +137,9 @@ namespace ImageProcessor.Samplers
height = source.Height * width / source.Width;
}
var processor = new Resize(sampler);
Resize processor = new Resize(sampler);
processor.OnProgress += progressHandler;
try
{
return source.Process(width, height, sourceRectangle, new Rectangle(0, 0, width, height), processor);
@ -169,8 +172,9 @@ namespace ImageProcessor.Samplers
/// <returns>The <see cref="Image"/></returns>
public static Image Rotate(this Image source, float degrees, IResampler sampler, ProgressEventHandler progressHandler = null)
{
var processor = new Rotate(sampler) { Angle = degrees };
Rotate processor = new Rotate(sampler) { Angle = degrees };
processor.OnProgress += progressHandler;
try
{
return source.Process(source.Width, source.Height, source.Bounds, source.Bounds, processor);
@ -191,8 +195,9 @@ namespace ImageProcessor.Samplers
/// <returns>The <see cref="Image"/></returns>
public static Image RotateFlip(this Image source, RotateType rotateType, FlipType flipType, ProgressEventHandler progressHandler = null)
{
var processor = new RotateFlip(rotateType, flipType);
RotateFlip processor = new RotateFlip(rotateType, flipType);
processor.OnProgress += progressHandler;
try
{
return source.Process(source.Width, source.Height, source.Bounds, source.Bounds, processor);

6
tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs

@ -65,9 +65,9 @@ namespace ImageProcessor.Tests
string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file);
using (FileStream output = File.OpenWrite($"TestOutput/Filter/{ Path.GetFileName(filename) }"))
{
processor.OnProgress += ProgressUpdate;
processor.OnProgress += this.ProgressUpdate;
image.Process(processor).Save(output);
processor.OnProgress -= ProgressUpdate;
processor.OnProgress -= this.ProgressUpdate;
}
Trace.WriteLine($"{ name }: { watch.ElapsedMilliseconds}ms");
@ -77,7 +77,7 @@ namespace ImageProcessor.Tests
private void ProgressUpdate(object sender, ProgressEventArgs e)
{
Assert.InRange(e.numRowsProcessed, 1, e.totalRows);
Assert.InRange(e.RowsProcessed, 1, e.TotalRows);
}
}
}

16
tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs

@ -57,7 +57,7 @@
string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file);
using (FileStream output = File.OpenWrite($"TestOutput/Resize/{filename}"))
{
image.Resize(image.Width / 2, image.Height / 2, sampler, ProgressUpdate)
image.Resize(image.Width / 2, image.Height / 2, sampler, this.ProgressUpdate)
.Save(output);
}
@ -85,7 +85,7 @@
string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file);
using (FileStream output = File.OpenWrite($"TestOutput/Resize/{filename}"))
{
image.Resize(image.Width / 3, 0, new TriangleResampler(), ProgressUpdate)
image.Resize(image.Width / 3, 0, new TriangleResampler(), this.ProgressUpdate)
.Save(output);
}
@ -113,7 +113,7 @@
string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file);
using (FileStream output = File.OpenWrite($"TestOutput/Resize/{filename}"))
{
image.Resize(0, image.Height / 3, new TriangleResampler(), ProgressUpdate)
image.Resize(0, image.Height / 3, new TriangleResampler(), this.ProgressUpdate)
.Save(output);
}
@ -140,7 +140,7 @@
string filename = Path.GetFileNameWithoutExtension(file) + "-" + rotateType + flipType + Path.GetExtension(file);
using (FileStream output = File.OpenWrite($"TestOutput/RotateFlip/{filename}"))
{
image.RotateFlip(rotateType, flipType, ProgressUpdate)
image.RotateFlip(rotateType, flipType, this.ProgressUpdate)
.Save(output);
}
@ -167,7 +167,7 @@
string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file);
using (FileStream output = File.OpenWrite($"TestOutput/Rotate/{filename}"))
{
image.Rotate(45, sampler, ProgressUpdate)
image.Rotate(45, sampler, this.ProgressUpdate)
//.BackgroundColor(Color.Aqua)
.Save(output);
}
@ -193,7 +193,7 @@
string filename = Path.GetFileNameWithoutExtension(file) + "-EntropyCrop" + Path.GetExtension(file);
using (FileStream output = File.OpenWrite($"TestOutput/EntropyCrop/{filename}"))
{
image.EntropyCrop(.5f, ProgressUpdate).Save(output);
image.EntropyCrop(.5f, this.ProgressUpdate).Save(output);
}
}
}
@ -215,7 +215,7 @@
string filename = Path.GetFileNameWithoutExtension(file) + "-Crop" + Path.GetExtension(file);
using (FileStream output = File.OpenWrite($"TestOutput/Crop/{filename}"))
{
image.Crop(image.Width / 2, image.Height / 2, ProgressUpdate).Save(output);
image.Crop(image.Width / 2, image.Height / 2, this.ProgressUpdate).Save(output);
}
}
}
@ -238,7 +238,7 @@
private void ProgressUpdate(object sender, ProgressEventArgs e)
{
Assert.InRange(e.numRowsProcessed, 1, e.totalRows);
Assert.InRange(e.RowsProcessed, 1, e.TotalRows);
}
}
}

Loading…
Cancel
Save