diff --git a/src/ImageProcessor.Playground/Program.cs b/src/ImageProcessor.Playground/Program.cs
index 5a4269aab..d34732b34 100644
--- a/src/ImageProcessor.Playground/Program.cs
+++ b/src/ImageProcessor.Playground/Program.cs
@@ -77,12 +77,12 @@ namespace ImageProcessor.PlayGround
//.ReplaceColor(Color.FromArgb(255, 1, 107, 165), Color.FromArgb(255, 1, 165, 13), 80)
//.Resize(layer)
//.DetectEdges(new KirschEdgeFilter())
- .DetectEdges(new LaplacianOfGaussianEdgeFilter())
+ //.DetectEdges(new LaplacianOfGaussianEdgeFilter())
//.EntropyCrop()
//.Filter(MatrixFilters.Comic)
//.Filter(MatrixFilters.Comic)
//.Filter(MatrixFilters.HiSatch)
- //.Pixelate(8)
+ .Pixelate(8)
//.GaussianSharpen(10)
.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name)));
diff --git a/src/ImageProcessor/Common/Extensions/EnumerableExtensions.cs b/src/ImageProcessor/Common/Extensions/EnumerableExtensions.cs
new file mode 100644
index 000000000..302ceaf78
--- /dev/null
+++ b/src/ImageProcessor/Common/Extensions/EnumerableExtensions.cs
@@ -0,0 +1,93 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// Copyright (c) James South.
+// Licensed under the Apache License, Version 2.0.
+//
+//
+// Encapsulates a series of time saving extension methods to the interface.
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace ImageProcessor.Common.Extensions
+{
+ using System;
+ using System.Collections.Generic;
+
+ ///
+ /// Encapsulates a series of time saving extension methods to the interface.
+ ///
+ public static class EnumerableExtensions
+ {
+ ///
+ /// Generates a sequence of integral numbers within a specified range.
+ ///
+ ///
+ /// The start index, inclusive.
+ ///
+ ///
+ /// The end index, exclusive.
+ ///
+ ///
+ /// The incremental step.
+ ///
+ ///
+ /// The that contains a range of sequential integral numbers.
+ ///
+ public static IEnumerable SteppedRange(int fromInclusive, int toExclusive, int step)
+ {
+ // Borrowed from Enumerable.Range
+ long num = (fromInclusive + toExclusive) - 1L;
+ if ((toExclusive < 0) || (num > 0x7fffffffL))
+ {
+ throw new ArgumentOutOfRangeException("toExclusive");
+ }
+
+ return RangeIterator(fromInclusive, i => i < toExclusive, step);
+ }
+
+ ///
+ /// Generates a sequence of integral numbers within a specified range.
+ ///
+ ///
+ /// The start index, inclusive.
+ ///
+ ///
+ /// A method that has one parameter and returns a calculating the end index
+ ///
+ ///
+ /// The incremental step.
+ ///
+ ///
+ /// The that contains a range of sequential integral numbers.
+ ///
+ public static IEnumerable SteppedRange(int fromInclusive, Func toDelegate, int step)
+ {
+ return RangeIterator(fromInclusive, toDelegate, step);
+ }
+
+ ///
+ /// Generates a sequence of integral numbers within a specified range.
+ ///
+ ///
+ /// The start index, inclusive.
+ ///
+ ///
+ /// A method that has one parameter and returns a calculating the end index
+ ///
+ ///
+ /// The incremental step.
+ ///
+ ///
+ /// The that contains a range of sequential integral numbers.
+ ///
+ private static IEnumerable RangeIterator(int fromInclusive, Func toDelegate, int step)
+ {
+ int i = fromInclusive;
+ while (toDelegate(i))
+ {
+ yield return i;
+ i += step;
+ }
+ }
+ }
+}
diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj
index c5f4a8146..5cb599083 100644
--- a/src/ImageProcessor/ImageProcessor.csproj
+++ b/src/ImageProcessor/ImageProcessor.csproj
@@ -125,6 +125,7 @@
+
diff --git a/src/ImageProcessor/Imaging/Filters/Artistic/OilPaintingFilter.cs b/src/ImageProcessor/Imaging/Filters/Artistic/OilPaintingFilter.cs
index d659f6203..2213c043a 100644
--- a/src/ImageProcessor/Imaging/Filters/Artistic/OilPaintingFilter.cs
+++ b/src/ImageProcessor/Imaging/Filters/Artistic/OilPaintingFilter.cs
@@ -12,6 +12,7 @@ namespace ImageProcessor.Imaging.Filters.Artistic
{
using System;
using System.Drawing;
+ using System.Threading.Tasks;
using ImageProcessor.Common.Extensions;
@@ -104,76 +105,81 @@ namespace ImageProcessor.Imaging.Filters.Artistic
{
using (FastBitmap destinationBitmap = new FastBitmap(destination))
{
- for (int y = 0; y < height; y++)
- {
- for (int x = 0; x < width; x++)
+ Parallel.For(
+ 0,
+ height,
+ y =>
{
- int maxIntensity = 0;
- int maxIndex = 0;
- int[] intensityBin = new int[this.levels];
- int[] blueBin = new int[this.levels];
- int[] greenBin = new int[this.levels];
- int[] redBin = new int[this.levels];
-
- for (int i = 0; i <= radius; i++)
+ for (int x = 0; x < width; x++)
{
- int ir = i - radius;
- int offsetY = y + ir;
-
- // Skip the current row
- if (offsetY < 0)
+ int maxIntensity = 0;
+ int maxIndex = 0;
+ int[] intensityBin = new int[this.levels];
+ int[] blueBin = new int[this.levels];
+ int[] greenBin = new int[this.levels];
+ int[] redBin = new int[this.levels];
+
+ for (int i = 0; i <= radius; i++)
{
- continue;
- }
-
- // Outwith the current bounds so break.
- if (offsetY >= height)
- {
- break;
- }
+ int ir = i - radius;
+ int offsetY = y + ir;
- for (int fx = 0; fx <= radius; fx++)
- {
- int jr = fx - radius;
- int offsetX = x + jr;
-
- // Skip the column
- if (offsetX < 0)
+ // Skip the current row
+ if (offsetY < 0)
{
continue;
}
- if (offsetX < width)
+ // Outwith the current bounds so break.
+ if (offsetY >= height)
{
- Color color = sourceBitmap.GetPixel(offsetX, offsetY);
-
- byte sourceBlue = color.B;
- byte sourceGreen = color.G;
- byte sourceRed = color.R;
+ break;
+ }
- int currentIntensity = (int)Math.Round(((sourceBlue + sourceGreen + sourceRed) / 3.0 * (this.levels - 1)) / 255.0);
+ for (int fx = 0; fx <= radius; fx++)
+ {
+ int jr = fx - radius;
+ int offsetX = x + jr;
- intensityBin[currentIntensity] += 1;
- blueBin[currentIntensity] += sourceBlue;
- greenBin[currentIntensity] += sourceGreen;
- redBin[currentIntensity] += sourceRed;
+ // Skip the column
+ if (offsetX < 0)
+ {
+ continue;
+ }
- if (intensityBin[currentIntensity] > maxIntensity)
+ if (offsetX < width)
{
- maxIntensity = intensityBin[currentIntensity];
- maxIndex = currentIntensity;
+ // ReSharper disable once AccessToDisposedClosure
+ Color color = sourceBitmap.GetPixel(offsetX, offsetY);
+
+ byte sourceBlue = color.B;
+ byte sourceGreen = color.G;
+ byte sourceRed = color.R;
+
+ int currentIntensity = (int)Math.Round(((sourceBlue + sourceGreen + sourceRed) / 3.0 * (this.levels - 1)) / 255.0);
+
+ intensityBin[currentIntensity] += 1;
+ blueBin[currentIntensity] += sourceBlue;
+ greenBin[currentIntensity] += sourceGreen;
+ redBin[currentIntensity] += sourceRed;
+
+ if (intensityBin[currentIntensity] > maxIntensity)
+ {
+ maxIntensity = intensityBin[currentIntensity];
+ maxIndex = currentIntensity;
+ }
}
}
}
- }
- byte blue = Math.Abs(blueBin[maxIndex] / maxIntensity).ToByte();
- byte green = Math.Abs(greenBin[maxIndex] / maxIntensity).ToByte();
- byte red = Math.Abs(redBin[maxIndex] / maxIntensity).ToByte();
+ byte blue = Math.Abs(blueBin[maxIndex] / maxIntensity).ToByte();
+ byte green = Math.Abs(greenBin[maxIndex] / maxIntensity).ToByte();
+ byte red = Math.Abs(redBin[maxIndex] / maxIntensity).ToByte();
- destinationBitmap.SetPixel(x, y, Color.FromArgb(red, green, blue));
- }
- }
+ // ReSharper disable once AccessToDisposedClosure
+ destinationBitmap.SetPixel(x, y, Color.FromArgb(red, green, blue));
+ }
+ });
}
}
diff --git a/src/ImageProcessor/Imaging/Filters/Photo/ComicMatrixFilter.cs b/src/ImageProcessor/Imaging/Filters/Photo/ComicMatrixFilter.cs
index 0f5bcad66..ac9d488af 100644
--- a/src/ImageProcessor/Imaging/Filters/Photo/ComicMatrixFilter.cs
+++ b/src/ImageProcessor/Imaging/Filters/Photo/ComicMatrixFilter.cs
@@ -15,6 +15,7 @@ namespace ImageProcessor.Imaging.Filters.Photo
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
+ using System.Threading.Tasks;
using ImageProcessor.Common.Extensions;
using ImageProcessor.Imaging.Filters.Artistic;
@@ -61,7 +62,7 @@ namespace ImageProcessor.Imaging.Filters.Photo
// Apply a oil painting filter to the image.
highBitmap = new OilPaintingFilter(3, 5).ApplyFilter((Bitmap)image);
-
+
// Draw the edges.
edgeBitmap = DrawEdges((Bitmap)image, 120);
@@ -383,19 +384,25 @@ namespace ImageProcessor.Imaging.Filters.Photo
int width = source.Width;
int height = source.Height;
- for (int y = 0; y < height; y++)
- {
- for (int x = 0; x < width; x++)
+ Parallel.For(
+ 0,
+ height,
+ y =>
{
- Color sourceColor = sourceBitmap.GetPixel(x, y);
- Color destinationColor = destinationBitmap.GetPixel(x, y);
-
- if (destinationColor.A != 0)
+ for (int x = 0; x < width; x++)
{
- destinationBitmap.SetPixel(x, y, Color.FromArgb(sourceColor.B, destinationColor.R, destinationColor.G, destinationColor.B));
+ // ReSharper disable AccessToDisposedClosure
+ Color sourceColor = sourceBitmap.GetPixel(x, y);
+ Color destinationColor = destinationBitmap.GetPixel(x, y);
+
+ if (destinationColor.A != 0)
+ {
+ destinationBitmap.SetPixel(x, y, Color.FromArgb(sourceColor.B, destinationColor.R, destinationColor.G, destinationColor.B));
+ }
+
+ // ReSharper restore AccessToDisposedClosure
}
- }
- }
+ });
}
}
}
diff --git a/src/ImageProcessor/Processors/Pixelate.cs b/src/ImageProcessor/Processors/Pixelate.cs
index 437388eb0..7724f9b3f 100644
--- a/src/ImageProcessor/Processors/Pixelate.cs
+++ b/src/ImageProcessor/Processors/Pixelate.cs
@@ -13,8 +13,10 @@ namespace ImageProcessor.Processors
using System;
using System.Collections.Generic;
using System.Drawing;
+ using System.Threading.Tasks;
using ImageProcessor.Common.Exceptions;
+ using ImageProcessor.Common.Extensions;
using ImageProcessor.Imaging;
///
@@ -82,37 +84,44 @@ namespace ImageProcessor.Processors
using (FastBitmap fastBitmap = new FastBitmap(newImage))
{
- for (int j = y; j < y + height && j < maxHeight; j += size)
- {
- for (int i = x; i < x + width && i < maxWidth; i += size)
- {
- int offsetX = offset;
- int offsetY = offset;
+ // Get the range of on the y-plane to choose from.
+ IEnumerable range = EnumerableExtensions.SteppedRange(y, i => i < y + height && i < maxHeight, size);
- // Make sure that the offset is within the boundary of the image.
- while (j + offsetY >= maxHeight)
+ Parallel.ForEach(
+ range,
+ j =>
+ {
+ for (int i = x; i < x + width && i < maxWidth; i += size)
{
- offsetY--;
- }
+ int offsetX = offset;
+ int offsetY = offset;
- while (i + offsetX >= maxWidth)
- {
- offsetX--;
- }
+ // Make sure that the offset is within the boundary of the image.
+ while (j + offsetY >= maxHeight)
+ {
+ offsetY--;
+ }
- // Get the pixel color in the centre of the soon to be pixelated area.
- Color pixel = fastBitmap.GetPixel(i + offsetX, j + offsetY);
+ while (i + offsetX >= maxWidth)
+ {
+ offsetX--;
+ }
- // For each pixel in the pixelate size, set it to the centre color.
- for (int l = j; l < j + size && l < maxHeight; l++)
- {
- for (int k = i; k < i + size && k < maxWidth; k++)
+ // Get the pixel color in the centre of the soon to be pixelated area.
+ // ReSharper disable AccessToDisposedClosure
+ Color pixel = fastBitmap.GetPixel(i + offsetX, j + offsetY);
+
+ // For each pixel in the pixelate size, set it to the centre color.
+ for (int l = j; l < j + size && l < maxHeight; l++)
{
- fastBitmap.SetPixel(k, l, pixel);
+ for (int k = i; k < i + size && k < maxWidth; k++)
+ {
+ fastBitmap.SetPixel(k, l, pixel);
+ }
}
+ // ReSharper restore AccessToDisposedClosure
}
- }
- }
+ });
}
image.Dispose();