Browse Source

Mergign rotate/hue. Init Replace colour

Former-commit-id: e31e62b5f0c1cea1f63c16e7638416bfe65962e4
af/merge-core
James South 12 years ago
parent
commit
74b8d05465
  1. 34
      src/ImageProcessor/ImageFactory.cs
  2. 1
      src/ImageProcessor/ImageProcessor.csproj
  3. 214
      src/ImageProcessor/Imaging/Convolution.cs
  4. 30
      src/ImageProcessor/Processors/Hue.cs
  5. 53
      src/ImageProcessor/Processors/ReplaceColor.cs
  6. 5
      src/ImageProcessorConsole/Program.cs

34
src/ImageProcessor/ImageFactory.cs

@ -603,37 +603,13 @@ namespace ImageProcessor
/// The angle by which to alter the images hue. /// The angle by which to alter the images hue.
/// Any integer between 0 and 360. /// Any integer between 0 and 360.
/// </param> /// </param>
/// <returns> /// <param name="rotate">
/// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class. /// Whether to rotate the hue of the current image altering each color
/// </returns>
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;
}
/// <summary>
/// Rotates the hue of the current image altering each color.
/// </summary>
/// <param name="degrees">
/// The angle by which to rotate the images hue.
/// Any integer between 0 and 360.
/// </param> /// </param>
/// <returns> /// <returns>
/// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class. /// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class.
/// </returns> /// </returns>
public ImageFactory HueRotate(int degrees) public ImageFactory Hue(int degrees, bool rotate = false)
{ {
// Sanitize the input. // Sanitize the input.
if (degrees > 360 || degrees < 0) if (degrees > 360 || degrees < 0)
@ -641,9 +617,9 @@ namespace ImageProcessor
degrees = 0; degrees = 0;
} }
if (this.ShouldProcess) if (this.ShouldProcess && degrees > 0)
{ {
HueRotate hue = new HueRotate { DynamicParameter = degrees }; Hue hue = new Hue { DynamicParameter = new Tuple<int, bool>(degrees, rotate) };
this.CurrentImageFormat.ApplyProcessor(hue.ProcessImage, this); this.CurrentImageFormat.ApplyProcessor(hue.ProcessImage, this);
} }

1
src/ImageProcessor/ImageProcessor.csproj

@ -122,7 +122,6 @@
<Compile Include="Processors\Brightness.cs" /> <Compile Include="Processors\Brightness.cs" />
<Compile Include="Processors\Contrast.cs" /> <Compile Include="Processors\Contrast.cs" />
<Compile Include="Processors\GaussianSharpen.cs" /> <Compile Include="Processors\GaussianSharpen.cs" />
<Compile Include="Processors\HueRotate.cs" />
<Compile Include="Processors\Hue.cs" /> <Compile Include="Processors\Hue.cs" />
<Compile Include="Processors\Meta.cs" /> <Compile Include="Processors\Meta.cs" />
<Compile Include="Processors\Pixelate.cs" /> <Compile Include="Processors\Pixelate.cs" />

214
src/ImageProcessor/Imaging/Convolution.cs

@ -264,145 +264,117 @@ namespace ImageProcessor.Imaging
{ {
int width = sourceBitmap.Width; int width = sourceBitmap.Width;
int height = sourceBitmap.Height; int height = sourceBitmap.Height;
Bitmap destinationBitmap = new Bitmap(width, height);
BitmapData sourceData = sourceBitmap.LockBits( using (FastBitmap sourceFastBitmap = new FastBitmap(sourceBitmap))
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++)
{ {
// For each pixel using (FastBitmap destinationFastBitmap = new FastBitmap(destinationBitmap))
for (int x = 0; x < width; x++)
{ {
// The number of kernel elements taken into account int kernelLength = kernel.GetLength(0);
int processedKernelSize; int radius = kernelLength >> 1;
int kernelSize = kernelLength * kernelLength;
int threshold = this.Threshold;
// Colour sums // For each line
double blue; for (int y = 0; y < height; y++)
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++)
{ {
int ir = i - radius; // For each pixel
int offsetY = y + ir; for (int x = 0; x < width; x++)
// Skip the current row
if (offsetY < 0)
{ {
continue; // The number of kernel elements taken into account
} int processedKernelSize;
// Outwith the current bounds so break. // Colour sums
if (offsetY >= height) double blue;
{ double alpha;
break; double divider;
} double green;
double red = green = blue = alpha = divider = processedKernelSize = 0;
// For each kernel column
for (int j = 0; j < kernelLength; j++) // For each kernel row
{ for (int i = 0; i < kernelLength; i++)
int jr = j - radius;
int offsetX = x + jr;
// Skip the column
if (offsetX < 0)
{ {
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); // All kernel elements are processed; we are not on the edge.
byte sourceBlue = pixelBuffer[calcOffset]; divider = this.Divider;
byte sourceGreen = pixelBuffer[calcOffset + 1]; }
byte sourceRed = pixelBuffer[calcOffset + 2]; else
byte sourceAlpha = pixelBuffer[calcOffset + 3]; {
// We are on an edge; do we need to use dynamic divider or not?
double k = kernel[i, j]; if (!this.UseDynamicDividerForEdges)
divider += k; {
// Apply the set divider.
red += k * sourceRed; divider = this.Divider;
green += k * sourceGreen; }
blue += k * sourceBlue; }
alpha += k * sourceAlpha;
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 // Add any applicable threshold.
if (processedKernelSize == kernelSize) red += threshold;
{ green += threshold;
// All kernel elements are processed; we are not on the edge. blue += threshold;
divider = this.Divider; alpha += threshold;
}
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;
}
}
// Check and apply the divider destinationFastBitmap.SetPixel(x, y, Color.FromArgb(alpha.ToByte(), red.ToByte(), green.ToByte(), blue.ToByte()));
if ((long)divider != 0) }
{
red /= divider;
green /= divider;
blue /= divider;
alpha /= divider;
} }
// 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); return destinationBitmap;
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;
} }
#region Private #region Private

30
src/ImageProcessor/Processors/Hue.cs

@ -57,7 +57,10 @@ namespace ImageProcessor.Processors
try try
{ {
int degrees = this.DynamicParameter;
Tuple<int, bool> parameters = this.DynamicParameter;
int degrees = parameters.Item1;
bool rotate = parameters.Item2;
int width = image.Width; int width = image.Width;
int height = image.Height; int height = image.Height;
@ -65,13 +68,28 @@ namespace ImageProcessor.Processors
using (FastBitmap fastBitmap = new FastBitmap(newImage)) 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)); for (int j = 0; j < height; j++)
HslaColor altered = HslaColor.FromHslaColor(degrees / 360f, original.S, original.L, original.A); {
fastBitmap.SetPixel(i, j, altered); 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);
}
} }
} }
} }

53
src/ImageProcessor/Processors/HueRotate.cs → src/ImageProcessor/Processors/ReplaceColor.cs

@ -1,31 +1,21 @@
// -------------------------------------------------------------------------------------------------------------------- namespace ImageProcessor.Processors
// <copyright file="HueRotate.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// Encapsulates methods to rotate the hue component of an image.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Processors
{ {
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using ImageProcessor.Common.Exceptions; using ImageProcessor.Common.Exceptions;
using ImageProcessor.Imaging; using ImageProcessor.Imaging;
using ImageProcessor.Imaging.Colors;
/// <summary> /// <summary>
/// Encapsulates methods to rotate the hue component of an image. /// Encapsulates methods allowing the replacement of a color within an image.
/// <see href="http://softwarebydefault.com/2013/03/16/bitmap-color-substitution/"/>
/// </summary> /// </summary>
public class HueRotate : IGraphicsProcessor public class ReplaceColor : IGraphicsProcessor
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HueRotate"/> class. /// Initializes a new instance of the <see cref="ReplaceColor"/> class.
/// </summary> /// </summary>
public HueRotate() public ReplaceColor()
{ {
this.Settings = new Dictionary<string, string>(); this.Settings = new Dictionary<string, string>();
} }
@ -33,12 +23,20 @@ namespace ImageProcessor.Processors
/// <summary> /// <summary>
/// Gets or sets the dynamic parameter. /// Gets or sets the dynamic parameter.
/// </summary> /// </summary>
public dynamic DynamicParameter { get; set; } public dynamic DynamicParameter
{
get;
set;
}
/// <summary> /// <summary>
/// Gets or sets any additional settings required by the processor. /// Gets or sets any additional settings required by the processor.
/// </summary> /// </summary>
public Dictionary<string, string> Settings { get; set; } public Dictionary<string, string> Settings
{
get;
set;
}
/// <summary> /// <summary>
/// Processes the image. /// Processes the image.
@ -57,27 +55,22 @@ namespace ImageProcessor.Processors
try try
{ {
int degrees = this.DynamicParameter; Tuple<Color, Color, int> parameters = this.DynamicParameter;
int width = image.Width; Color original = parameters.Item1;
int height = image.Height; Color replacement = parameters.Item2;
int threshold = parameters.Item3;
newImage = new Bitmap(image); newImage = new Bitmap(image);
using (FastBitmap fastBitmap = new FastBitmap(newImage)) 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.Dispose();
image = newImage; image = newImage;
} }
catch (Exception ex) catch (Exception ex)
{ {

5
src/ImageProcessorConsole/Program.cs

@ -73,9 +73,10 @@ namespace ImageProcessorConsole
//.BackgroundColor(Color.White) //.BackgroundColor(Color.White)
//.Resize(new Size((int)(size.Width * 1.1), 0)) //.Resize(new Size((int)(size.Width * 1.1), 0))
//.ContentAwareResize(layer) //.ContentAwareResize(layer)
//.Constrain(size) .Constrain(size)
//.Filter(MatrixFilters.HiSatch) //.Filter(MatrixFilters.HiSatch)
.Pixelate(8) //.Pixelate(8)
.GaussianSharpen(10)
.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name))); .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name)));
stopwatch.Stop(); stopwatch.Stop();

Loading…
Cancel
Save