From 09786d26274bb273e80ab1a4dbf27e4ed668b257 Mon Sep 17 00:00:00 2001 From: voidstar69 Date: Sat, 23 Jan 2016 18:44:32 +0000 Subject: [PATCH] Added progress callback to IImageProcessor and ParallelImageProcessor Former-commit-id: 837027deaf8f46ed9dc6b9adf50d7fa3596de04d Former-commit-id: cc005f037f4e6d9ead5763ab73c49abe09aadbe4 Former-commit-id: 2036768cdc0c07c71f746a5c0eb64633c2893f3a --- src/ImageProcessor/Filters/Brightness.cs | 1 + src/ImageProcessor/IImageProcessor.cs | 17 ++++++++++ src/ImageProcessor/ParallelImageProcessor.cs | 33 +++++++++++++++++++ .../Processors/Filters/FilterTests.cs | 14 ++++++++ 4 files changed, 65 insertions(+) diff --git a/src/ImageProcessor/Filters/Brightness.cs b/src/ImageProcessor/Filters/Brightness.cs index 6a5ae3985..73c8b377f 100644 --- a/src/ImageProcessor/Filters/Brightness.cs +++ b/src/ImageProcessor/Filters/Brightness.cs @@ -57,6 +57,7 @@ namespace ImageProcessor.Filters target[x, y] = Color.Compress(new Color(vector3, color.A)); } + this.OnRowProcessed(); } }); } diff --git a/src/ImageProcessor/IImageProcessor.cs b/src/ImageProcessor/IImageProcessor.cs index b9b90cbe0..8e31c4e1d 100644 --- a/src/ImageProcessor/IImageProcessor.cs +++ b/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); + /// /// Encapsulates methods to alter the pixels of an image. /// public interface IImageProcessor { + /// + /// Event fires when each row of the source image has been processed. + /// + /// + /// 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. + /// + event ProgressedEventHandler OnProgressed; + /// /// Applies the process to the specified portion of the specified . /// diff --git a/src/ImageProcessor/ParallelImageProcessor.cs b/src/ImageProcessor/ParallelImageProcessor.cs index a5ea2ad76..4f34dd61d 100644 --- a/src/ImageProcessor/ParallelImageProcessor.cs +++ b/src/ImageProcessor/ParallelImageProcessor.cs @@ -6,6 +6,7 @@ namespace ImageProcessor { using System; + using System.Threading; using System.Threading.Tasks; /// @@ -13,11 +14,38 @@ namespace ImageProcessor /// public abstract class ParallelImageProcessor : IImageProcessor { + /// + public event ProgressedEventHandler OnProgressed; + /// /// Gets or sets the count of workers to run the process in parallel. /// public virtual int Parallelism { get; set; } = Environment.ProcessorCount * 2; + /// + /// The number of rows processed by a derived class. + /// + private int numRowsProcessed; + + /// + /// The total number of rows that will be processed by a derived class. + /// + private int totalRows; + + /// + /// Must be called by derived classes after processing a single row. + /// + 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 }); + } + } + /// 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) { diff --git a/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs b/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs index c3b26590c..3a24da33e 100644 --- a/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs +++ b/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; + } } }