From d603133e8de800c73b45aa9ca16a715d43a7ed0c Mon Sep 17 00:00:00 2001 From: James South Date: Fri, 19 Sep 2014 16:15:21 +0100 Subject: [PATCH] Mergign rotate/hue. Init Replace colour Former-commit-id: fb8999c801f68e9e0953373ef4f1f9e4b6806e75 --- src/ImageProcessor/ImageFactory.cs | 34 +-- src/ImageProcessor/ImageProcessor.csproj | 1 - src/ImageProcessor/Imaging/Convolution.cs | 214 ++++++++---------- src/ImageProcessor/Processors/Hue.cs | 30 ++- .../{HueRotate.cs => ReplaceColor.cs} | 53 ++--- src/ImageProcessorConsole/Program.cs | 5 +- 6 files changed, 148 insertions(+), 189 deletions(-) rename src/ImageProcessor/Processors/{HueRotate.cs => ReplaceColor.cs} (52%) diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs index b27686231a..510803eb54 100644 --- a/src/ImageProcessor/ImageFactory.cs +++ b/src/ImageProcessor/ImageFactory.cs @@ -603,37 +603,13 @@ namespace ImageProcessor /// The angle by which to alter the images hue. /// Any integer between 0 and 360. /// - /// - /// The current instance of the class. - /// - public ImageFactory Hue(int degrees) - { - // Sanitize the input. - if (degrees > 360 || degrees < 0) - { - degrees = 0; - } - - if (this.ShouldProcess) - { - Hue hue = new Hue { DynamicParameter = degrees }; - this.CurrentImageFormat.ApplyProcessor(hue.ProcessImage, this); - } - - return this; - } - - /// - /// Rotates the hue of the current image altering each color. - /// - /// - /// The angle by which to rotate the images hue. - /// Any integer between 0 and 360. + /// + /// Whether to rotate the hue of the current image altering each color /// /// /// The current instance of the class. /// - public ImageFactory HueRotate(int degrees) + public ImageFactory Hue(int degrees, bool rotate = false) { // Sanitize the input. if (degrees > 360 || degrees < 0) @@ -641,9 +617,9 @@ namespace ImageProcessor degrees = 0; } - if (this.ShouldProcess) + if (this.ShouldProcess && degrees > 0) { - HueRotate hue = new HueRotate { DynamicParameter = degrees }; + Hue hue = new Hue { DynamicParameter = new Tuple(degrees, rotate) }; this.CurrentImageFormat.ApplyProcessor(hue.ProcessImage, this); } diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index a3835a0610..48106d7c4b 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -122,7 +122,6 @@ - diff --git a/src/ImageProcessor/Imaging/Convolution.cs b/src/ImageProcessor/Imaging/Convolution.cs index bc8496ab27..c44d055c02 100644 --- a/src/ImageProcessor/Imaging/Convolution.cs +++ b/src/ImageProcessor/Imaging/Convolution.cs @@ -264,145 +264,117 @@ namespace ImageProcessor.Imaging { int width = sourceBitmap.Width; int height = sourceBitmap.Height; + Bitmap destinationBitmap = new Bitmap(width, height); - BitmapData sourceData = sourceBitmap.LockBits( - new Rectangle(0, 0, width, height), - ImageLockMode.ReadOnly, - PixelFormat.Format32bppArgb); - - int strideWidth = sourceData.Stride; - int scanHeight = sourceData.Height; - - int bufferSize = strideWidth * scanHeight; - byte[] pixelBuffer = new byte[bufferSize]; - byte[] resultBuffer = new byte[bufferSize]; - - Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length); - sourceBitmap.UnlockBits(sourceData); - - int kernelLength = kernel.GetLength(0); - int radius = kernelLength >> 1; - int kernelSize = kernelLength * kernelLength; - - // For each line - for (int y = 0; y < height; y++) + using (FastBitmap sourceFastBitmap = new FastBitmap(sourceBitmap)) { - // For each pixel - for (int x = 0; x < width; x++) + using (FastBitmap destinationFastBitmap = new FastBitmap(destinationBitmap)) { - // The number of kernel elements taken into account - int processedKernelSize; + int kernelLength = kernel.GetLength(0); + int radius = kernelLength >> 1; + int kernelSize = kernelLength * kernelLength; + int threshold = this.Threshold; - // Colour sums - double blue; - double alpha; - double divider; - double green; - double red = green = blue = alpha = divider = processedKernelSize = 0; - - // The location of the pixel bytes. - int byteOffset = (y * strideWidth) + (x * 4); - - // For each kernel row - for (int i = 0; i < kernelLength; i++) + // For each line + for (int y = 0; y < height; y++) { - int ir = i - radius; - int offsetY = y + ir; - - // Skip the current row - if (offsetY < 0) + // For each pixel + for (int x = 0; x < width; x++) { - continue; - } - - // Outwith the current bounds so break. - if (offsetY >= height) - { - break; - } - - // For each kernel column - for (int j = 0; j < kernelLength; j++) - { - int jr = j - radius; - int offsetX = x + jr; - - // Skip the column - if (offsetX < 0) + // The number of kernel elements taken into account + int processedKernelSize; + + // Colour sums + double blue; + double alpha; + double divider; + double green; + double red = green = blue = alpha = divider = processedKernelSize = 0; + + // For each kernel row + for (int i = 0; i < kernelLength; i++) { - continue; + int ir = i - radius; + int offsetY = y + ir; + + // Skip the current row + if (offsetY < 0) + { + continue; + } + + // Outwith the current bounds so break. + if (offsetY >= height) + { + break; + } + + // For each kernel column + for (int j = 0; j < kernelLength; j++) + { + int jr = j - radius; + int offsetX = x + jr; + + // Skip the column + if (offsetX < 0) + { + continue; + } + + if (offsetX < width) + { + Color color = sourceFastBitmap.GetPixel(offsetX, offsetY); + double k = kernel[i, j]; + divider += k; + + red += k * color.R; + green += k * color.G; + blue += k * color.B; + alpha += k * color.A; + + processedKernelSize++; + } + } } - if (offsetX < width) + // Check to see if all kernel elements were processed + if (processedKernelSize == kernelSize) { - int calcOffset = (offsetX * 4) + (offsetY * sourceData.Stride); - byte sourceBlue = pixelBuffer[calcOffset]; - byte sourceGreen = pixelBuffer[calcOffset + 1]; - byte sourceRed = pixelBuffer[calcOffset + 2]; - byte sourceAlpha = pixelBuffer[calcOffset + 3]; - - double k = kernel[i, j]; - divider += k; - - red += k * sourceRed; - green += k * sourceGreen; - blue += k * sourceBlue; - alpha += k * sourceAlpha; + // All kernel elements are processed; we are not on the edge. + divider = this.Divider; + } + else + { + // We are on an edge; do we need to use dynamic divider or not? + if (!this.UseDynamicDividerForEdges) + { + // Apply the set divider. + divider = this.Divider; + } + } - processedKernelSize++; + // Check and apply the divider + if ((long)divider != 0) + { + red /= divider; + green /= divider; + blue /= divider; + alpha /= divider; } - } - } - // Check to see if all kernel elements were processed - if (processedKernelSize == kernelSize) - { - // All kernel elements are processed; we are not on the edge. - divider = this.Divider; - } - else - { - // We are on an edge; do we need to use dynamic divider or not? - if (!this.UseDynamicDividerForEdges) - { - // Apply the set divider. - divider = this.Divider; - } - } + // Add any applicable threshold. + red += threshold; + green += threshold; + blue += threshold; + alpha += threshold; - // Check and apply the divider - if ((long)divider != 0) - { - red /= divider; - green /= divider; - blue /= divider; - alpha /= divider; + destinationFastBitmap.SetPixel(x, y, Color.FromArgb(alpha.ToByte(), red.ToByte(), green.ToByte(), blue.ToByte())); + } } - - // Add any applicable threshold. - red += this.Threshold; - green += this.Threshold; - blue += this.Threshold; - alpha += this.Threshold; - - resultBuffer[byteOffset] = blue.ToByte(); - resultBuffer[byteOffset + 1] = green.ToByte(); - resultBuffer[byteOffset + 2] = red.ToByte(); - resultBuffer[byteOffset + 3] = alpha.ToByte(); } } - Bitmap resultBitmap = new Bitmap(width, height); - - BitmapData resultData = resultBitmap.LockBits( - new Rectangle(0, 0, width, height), - ImageLockMode.WriteOnly, - PixelFormat.Format32bppArgb); - - Marshal.Copy(resultBuffer, 0, resultData.Scan0, resultBuffer.Length); - resultBitmap.UnlockBits(resultData); - - return resultBitmap; + return destinationBitmap; } #region Private diff --git a/src/ImageProcessor/Processors/Hue.cs b/src/ImageProcessor/Processors/Hue.cs index 2c59dcc542..4d049c676e 100644 --- a/src/ImageProcessor/Processors/Hue.cs +++ b/src/ImageProcessor/Processors/Hue.cs @@ -57,7 +57,10 @@ namespace ImageProcessor.Processors try { - int degrees = this.DynamicParameter; + + Tuple parameters = this.DynamicParameter; + int degrees = parameters.Item1; + bool rotate = parameters.Item2; int width = image.Width; int height = image.Height; @@ -65,13 +68,28 @@ namespace ImageProcessor.Processors using (FastBitmap fastBitmap = new FastBitmap(newImage)) { - for (int i = 0; i < width; i++) + if (!rotate) + { + for (int i = 0; i < width; i++) + { + for (int j = 0; j < height; j++) + { + HslaColor original = HslaColor.FromColor(fastBitmap.GetPixel(i, j)); + HslaColor altered = HslaColor.FromHslaColor(degrees / 360f, original.S, original.L, original.A); + fastBitmap.SetPixel(i, j, altered); + } + } + } + else { - for (int j = 0; j < height; j++) + for (int i = 0; i < width; i++) { - HslaColor original = HslaColor.FromColor(fastBitmap.GetPixel(i, j)); - HslaColor altered = HslaColor.FromHslaColor(degrees / 360f, original.S, original.L, original.A); - fastBitmap.SetPixel(i, j, altered); + for (int j = 0; j < height; j++) + { + HslaColor original = HslaColor.FromColor(fastBitmap.GetPixel(i, j)); + HslaColor altered = HslaColor.FromHslaColor((original.H + (degrees / 360f)) % 1, original.S, original.L, original.A); + fastBitmap.SetPixel(i, j, altered); + } } } } diff --git a/src/ImageProcessor/Processors/HueRotate.cs b/src/ImageProcessor/Processors/ReplaceColor.cs similarity index 52% rename from src/ImageProcessor/Processors/HueRotate.cs rename to src/ImageProcessor/Processors/ReplaceColor.cs index 9d99af892b..37b59b9353 100644 --- a/src/ImageProcessor/Processors/HueRotate.cs +++ b/src/ImageProcessor/Processors/ReplaceColor.cs @@ -1,31 +1,21 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) James South. -// Licensed under the Apache License, Version 2.0. -// -// -// Encapsulates methods to rotate the hue component of an image. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace ImageProcessor.Processors +namespace ImageProcessor.Processors { using System; using System.Collections.Generic; using System.Drawing; using ImageProcessor.Common.Exceptions; using ImageProcessor.Imaging; - using ImageProcessor.Imaging.Colors; /// - /// Encapsulates methods to rotate the hue component of an image. + /// Encapsulates methods allowing the replacement of a color within an image. + /// /// - public class HueRotate : IGraphicsProcessor + public class ReplaceColor : IGraphicsProcessor { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public HueRotate() + public ReplaceColor() { this.Settings = new Dictionary(); } @@ -33,12 +23,20 @@ namespace ImageProcessor.Processors /// /// Gets or sets the dynamic parameter. /// - public dynamic DynamicParameter { get; set; } + public dynamic DynamicParameter + { + get; + set; + } /// /// Gets or sets any additional settings required by the processor. /// - public Dictionary Settings { get; set; } + public Dictionary Settings + { + get; + set; + } /// /// Processes the image. @@ -57,27 +55,22 @@ namespace ImageProcessor.Processors try { - int degrees = this.DynamicParameter; - int width = image.Width; - int height = image.Height; + Tuple parameters = this.DynamicParameter; + Color original = parameters.Item1; + Color replacement = parameters.Item2; + int threshold = parameters.Item3; newImage = new Bitmap(image); using (FastBitmap fastBitmap = new FastBitmap(newImage)) { - for (int i = 0; i < width; i++) - { - for (int j = 0; j < height; j++) - { - HslaColor original = HslaColor.FromColor(fastBitmap.GetPixel(i, j)); - HslaColor altered = HslaColor.FromHslaColor((original.H + (degrees / 360f)) % 1, original.S, original.L, original.A); - fastBitmap.SetPixel(i, j, altered); - } - } + + } image.Dispose(); image = newImage; + } catch (Exception ex) { diff --git a/src/ImageProcessorConsole/Program.cs b/src/ImageProcessorConsole/Program.cs index 89a510e253..4b7651445c 100644 --- a/src/ImageProcessorConsole/Program.cs +++ b/src/ImageProcessorConsole/Program.cs @@ -73,9 +73,10 @@ namespace ImageProcessorConsole //.BackgroundColor(Color.White) //.Resize(new Size((int)(size.Width * 1.1), 0)) //.ContentAwareResize(layer) - //.Constrain(size) + .Constrain(size) //.Filter(MatrixFilters.HiSatch) - .Pixelate(8) + //.Pixelate(8) + .GaussianSharpen(10) .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name))); stopwatch.Stop();