Browse Source

Added progress callback to IImageProcessor and ParallelImageProcessor

Former-commit-id: 837027deaf8f46ed9dc6b9adf50d7fa3596de04d
Former-commit-id: cc005f037f4e6d9ead5763ab73c49abe09aadbe4
Former-commit-id: 2036768cdc0c07c71f746a5c0eb64633c2893f3a
af/merge-core
voidstar69 10 years ago
parent
commit
09786d2627
  1. 1
      src/ImageProcessor/Filters/Brightness.cs
  2. 17
      src/ImageProcessor/IImageProcessor.cs
  3. 33
      src/ImageProcessor/ParallelImageProcessor.cs
  4. 14
      tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs

1
src/ImageProcessor/Filters/Brightness.cs

@ -57,6 +57,7 @@ namespace ImageProcessor.Filters
target[x, y] = Color.Compress(new Color(vector3, color.A));
}
this.OnRowProcessed();
}
});
}

17
src/ImageProcessor/IImageProcessor.cs

@ -5,11 +5,28 @@
namespace ImageProcessor
{
public struct ProgressedEventArgs
{
public int numRowsProcessed;
public int totalRows;
}
public delegate void ProgressedEventHandler(object sender, ProgressedEventArgs e);
/// <summary>
/// Encapsulates methods to alter the pixels of an image.
/// </summary>
public interface IImageProcessor
{
/// <summary>
/// Event fires when each row of the source image has been processed.
/// </summary>
/// <remarks>
/// This event may be called from threads other than the client thread, and from multiple threads simultaneously.
/// Individual row notifications may arrived out of order.
/// </remarks>
event ProgressedEventHandler OnProgressed;
/// <summary>
/// Applies the process to the specified portion of the specified <see cref="ImageBase"/>.
/// </summary>

33
src/ImageProcessor/ParallelImageProcessor.cs

@ -6,6 +6,7 @@
namespace ImageProcessor
{
using System;
using System.Threading;
using System.Threading.Tasks;
/// <summary>
@ -13,11 +14,38 @@ namespace ImageProcessor
/// </summary>
public abstract class ParallelImageProcessor : IImageProcessor
{
/// <inheritdoc/>
public event ProgressedEventHandler OnProgressed;
/// <summary>
/// Gets or sets the count of workers to run the process in parallel.
/// </summary>
public virtual int Parallelism { get; set; } = Environment.ProcessorCount * 2;
/// <summary>
/// The number of rows processed by a derived class.
/// </summary>
private int numRowsProcessed;
/// <summary>
/// The total number of rows that will be processed by a derived class.
/// </summary>
private int totalRows;
/// <summary>
/// Must be called by derived classes after processing a single row.
/// </summary>
protected void OnRowProcessed()
{
if(this.OnProgressed != null)
{
int currThreadNumRows = Interlocked.Add(ref this.numRowsProcessed, 1);
// Report progress. This may be on the client's thread, or on a Task library thread.
this.OnProgressed(this, new ProgressedEventArgs { numRowsProcessed = currThreadNumRows, totalRows = this.totalRows });
}
}
/// <inheritdoc/>
public void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle)
{
@ -26,6 +54,9 @@ namespace ImageProcessor
Image temp = frame != null ? new Image(frame) : new Image((Image)source);
this.OnApply(temp, target, target.Bounds, sourceRectangle);
this.numRowsProcessed = 0;
this.totalRows = sourceRectangle.Height;
if (this.Parallelism > 1)
{
int partitionCount = this.Parallelism;
@ -72,6 +103,8 @@ namespace ImageProcessor
this.OnApply(temp, target, target.Bounds, sourceRectangle);
targetRectangle = target.Bounds;
this.numRowsProcessed = 0;
this.totalRows = targetRectangle.Bottom;
if (this.Parallelism > 1)
{

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

@ -1,6 +1,7 @@

namespace ImageProcessor.Tests
{
using System;
using System.Diagnostics;
using System.IO;
@ -65,12 +66,25 @@ namespace ImageProcessor.Tests
string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file);
using (FileStream output = File.OpenWrite($"TestOutput/Filter/{ Path.GetFileName(filename) }"))
{
lastRowProcessed = 0;
processor.OnProgressed += ProgressUpdate;
image.Process(processor).Save(output);
processor.OnProgressed -= ProgressUpdate;
}
Trace.WriteLine($"{ name }: { watch.ElapsedMilliseconds}ms");
}
}
}
private static int allowedVariability = Environment.ProcessorCount * 4;
private int lastRowProcessed;
private void ProgressUpdate(object sender, ProgressedEventArgs e)
{
Assert.InRange(e.numRowsProcessed, 1, e.totalRows);
Assert.InRange(e.numRowsProcessed, lastRowProcessed - allowedVariability, lastRowProcessed + allowedVariability);
lastRowProcessed = e.numRowsProcessed;
}
}
}

Loading…
Cancel
Save