Browse Source

Initial addition of hue adjustment processor

Former-commit-id: 6bae314ea0932804874ab3bee1cade7d1dd3d0ee
pull/17/head
James South 12 years ago
parent
commit
883afcfb10
  1. 4
      src/ImageProcessor.sln.DotSettings
  2. 27
      src/ImageProcessor/ImageFactory.cs
  3. 4
      src/ImageProcessor/ImageProcessor.csproj
  4. 359
      src/ImageProcessor/Imaging/Colors/HSLAColor.cs
  5. 109
      src/ImageProcessor/Imaging/Colors/RGBAColor.cs
  6. 256
      src/ImageProcessor/Imaging/FastBitmap.cs
  7. 93
      src/ImageProcessor/Imaging/Filters/ComicMatrixFilter.cs
  8. 2
      src/ImageProcessor/Processors/Alpha.cs
  9. 96
      src/ImageProcessor/Processors/Hue.cs
  10. 28
      src/ImageProcessorConsole/Program.cs
  11. 0
      src/ImageProcessorConsole/images/input/1aaa.jpg.REMOVED.git-id
  12. 1
      src/ImageProcessorConsole/images/input/IC580196.jpg.REMOVED.git-id
  13. BIN
      src/ImageProcessorConsole/images/input/Turtle.jpg
  14. BIN
      src/ImageProcessorConsole/images/input/sample1.jpg
  15. 1
      src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id
  16. BIN
      src/ImageProcessorConsole/images/output/1aaa.jpg
  17. BIN
      src/ImageProcessorConsole/images/output/2006-citybus.jpg
  18. 1
      src/ImageProcessorConsole/images/output/2006-citybus.jpg.REMOVED.git-id
  19. 2
      src/ImageProcessorConsole/images/output/2008.jpg.REMOVED.git-id
  20. BIN
      src/ImageProcessorConsole/images/output/2012-citybus.jpg
  21. 1
      src/ImageProcessorConsole/images/output/2012-citybus.jpg.REMOVED.git-id
  22. BIN
      src/ImageProcessorConsole/images/output/4.sm.webp
  23. 2
      src/ImageProcessorConsole/images/output/Arc-de-Triomphe-France.jpg.REMOVED.git-id
  24. BIN
      src/ImageProcessorConsole/images/output/IC580196.jpg
  25. 1
      src/ImageProcessorConsole/images/output/Image with gaps.jpg.REMOVED.git-id
  26. 1
      src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id
  27. BIN
      src/ImageProcessorConsole/images/output/Turtle.jpg
  28. BIN
      src/ImageProcessorConsole/images/output/arc_de_triomphe_paris_france.jpg
  29. 1
      src/ImageProcessorConsole/images/output/arc_de_triomphe_paris_france.jpg.REMOVED.git-id
  30. BIN
      src/ImageProcessorConsole/images/output/circle.png
  31. 1
      src/ImageProcessorConsole/images/output/monster.png.REMOVED.git-id
  32. BIN
      src/ImageProcessorConsole/images/output/mountain.jpg
  33. 1
      src/ImageProcessorConsole/images/output/mountain.jpg.REMOVED.git-id
  34. 1
      src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id
  35. BIN
      src/ImageProcessorConsole/images/output/night-bridge.jpg
  36. BIN
      src/ImageProcessorConsole/images/output/rotate.jpg
  37. 1
      src/ImageProcessorConsole/images/output/rotate.jpg.REMOVED.git-id
  38. BIN
      src/ImageProcessorConsole/images/output/sample1.jpg
  39. BIN
      src/ImageProcessorConsole/images/output/shutterstock_19173982_Arc_de_triomphe-square1.jpg
  40. 1
      src/ImageProcessorConsole/images/output/shutterstock_19173982_Arc_de_triomphe-square1.jpg.REMOVED.git-id
  41. BIN
      src/ImageProcessorConsole/images/output/test.jpg
  42. 1
      src/ImageProcessorConsole/images/output/test.jpg.REMOVED.git-id
  43. BIN
      src/ImageProcessorConsole/images/output/test.webp
  44. BIN
      src/ImageProcessorConsole/images/output/tower.jpg
  45. 1
      src/ImageProcessorConsole/images/output/tower.jpg.REMOVED.git-id

4
src/ImageProcessor.sln.DotSettings

@ -4,6 +4,8 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DT/@EntryIndexedValue">DT</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=FPX/@EntryIndexedValue">FPX</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=FR/@EntryIndexedValue">FR</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HSL/@EntryIndexedValue">HSL</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HSLA/@EntryIndexedValue">HSLA</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ICC/@EntryIndexedValue">ICC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ISO/@EntryIndexedValue">ISO</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=JPEG/@EntryIndexedValue">JPEG</s:String>
@ -14,5 +16,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MD/@EntryIndexedValue">MD</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OECF/@EntryIndexedValue">OECF</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=REF/@EntryIndexedValue">REF</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RGB/@EntryIndexedValue">RGB</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RGBA/@EntryIndexedValue">RGBA</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SRGB/@EntryIndexedValue">SRGB</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SS/@EntryIndexedValue">SS</s:String></wpf:ResourceDictionary>

27
src/ImageProcessor/ImageFactory.cs

@ -596,6 +596,33 @@ namespace ImageProcessor
return this;
}
/// <summary>
/// Changes the hue of the current image.
/// </summary>
/// <param name="degrees">
/// The angle by which to alter the images hue.
/// Any integer between 0 and 359.
/// </param>
/// <returns>
/// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class.
/// </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>
/// Alters the output quality of the current image.
/// <remarks>

4
src/ImageProcessor/ImageProcessor.csproj

@ -70,6 +70,9 @@
<Compile Include="Common\Extensions\DoubleExtensions.cs" />
<Compile Include="Configuration\NativeBinaryFactory.cs" />
<Compile Include="Configuration\NativeMethods.cs" />
<Compile Include="Imaging\Colors\HSLColor.cs" />
<Compile Include="Imaging\Colors\RGBAColor.cs" />
<Compile Include="Imaging\FastBitmap.cs" />
<Compile Include="Imaging\Formats\GifInfo.cs" />
<Compile Include="Common\Extensions\IntegerExtensions.cs" />
<Compile Include="Common\Exceptions\ImageFormatException.cs" />
@ -118,6 +121,7 @@
<Compile Include="Processors\Brightness.cs" />
<Compile Include="Processors\Contrast.cs" />
<Compile Include="Processors\GaussianSharpen.cs" />
<Compile Include="Processors\Hue.cs" />
<Compile Include="Processors\Meta.cs" />
<Compile Include="Processors\RoundedCorners.cs" />
<Compile Include="Processors\Saturation.cs" />

359
src/ImageProcessor/Imaging/Colors/HSLAColor.cs

@ -0,0 +1,359 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="HSLAColor.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Imaging.Colors
{
using System;
using System.Drawing;
/// <summary>
/// Represents an HSLA (hue, saturation, luminosity, alpha) color.
/// </summary>
public struct HSLAColor
{
// Private data members below are on scale 0-1
// They are scaled for use externally based on scale
/// <summary>
/// The hue component.
/// </summary>
private double hue;
/// <summary>
/// The luminosity component.
/// </summary>
private double luminosity;
/// <summary>
/// The saturation component.
/// </summary>
private double saturation;
/// <summary>
/// The alpha component.
/// </summary>
private double a;
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="HSLAColor"/> struct.
/// </summary>
/// <param name="color">
/// The color.
/// </param>
public HSLAColor(Color color)
: this()
{
this.SetRGBA(color.R, color.G, color.B, color.A);
}
/// <summary>
/// Initializes a new instance of the <see cref="HSLAColor"/> class.
/// </summary>
/// <param name="red">
/// The red.
/// </param>
/// <param name="green">
/// The green.
/// </param>
/// <param name="blue">
/// The blue.
/// </param>
public HSLAColor(int red, int green, int blue, int alpha)
: this()
{
this.SetRGBA(red, green, blue, alpha);
}
/// <summary>
/// Initializes a new instance of the <see cref="HSLAColor"/> class.
/// </summary>
/// <param name="hue">
/// The hue.
/// </param>
/// <param name="saturation">
/// The saturation.
/// </param>
/// <param name="luminosity">
/// The luminosity.
/// </param>
public HSLAColor(double hue, double saturation, double luminosity)
: this()
{
this.Hue = hue;
this.Saturation = saturation;
this.Luminosity = luminosity;
}
#endregion
#region Public Properties
/// <summary>
/// Gets or sets the hue.
/// </summary>
public double Hue
{
get
{
return this.hue;
}
set
{
this.hue = this.CheckRange(value);
}
}
/// <summary>
/// Gets or sets the luminosity.
/// </summary>
public double Luminosity
{
get
{
return this.luminosity;
}
set
{
this.luminosity = this.CheckRange(value);
}
}
/// <summary>
/// Gets or sets the saturation.
/// </summary>
public double Saturation
{
get
{
return this.saturation;
}
set
{
this.saturation = this.CheckRange(value);
}
}
#endregion
#region Public Methods and Operators
/// <summary>
/// The op_ implicit.
/// </summary>
/// <param name="hslColor">
/// The hsl color.
/// </param>
/// <returns>
/// </returns>
public static implicit operator Color(HSLAColor hslColor)
{
double r = 0, g = 0, b = 0;
if (Math.Abs(hslColor.luminosity - 0) > .0001)
{
if (Math.Abs(hslColor.saturation - 0) <= .0001)
{
r = g = b = hslColor.luminosity;
}
else
{
double temp2 = GetTemp2(hslColor);
double temp1 = (2.0 * hslColor.luminosity) - temp2;
r = GetColorComponent(temp1, temp2, hslColor.hue + (1.0 / 3.0));
g = GetColorComponent(temp1, temp2, hslColor.hue);
b = GetColorComponent(temp1, temp2, hslColor.hue - (1.0 / 3.0));
}
}
return Color.FromArgb((int)(255 * r), (int)(255 * g), (int)(255 * b));
}
/// <summary>
/// The op_ implicit.
/// </summary>
/// <param name="color">
/// The color.
/// </param>
/// <returns>
/// </returns>
public static implicit operator HSLAColor(Color color)
{
HSLAColor hslColor = new HSLAColor
{
hue = color.GetHue() / 360.0,
luminosity = color.GetBrightness(),
saturation = color.GetSaturation()
};
return hslColor;
}
/// <summary>
/// The set rgb components.
/// </summary>
/// <param name="red">
/// The red.
/// </param>
/// <param name="green">
/// The green component.
/// </param>
/// <param name="blue">
/// The blue component.
/// </param>
/// <param name="alpha">
/// The alpha component.
/// </param>
public void SetRGBA(int red, int green, int blue, int alpha)
{
HSLAColor hslColor = Color.FromArgb(alpha, red, green, blue);
this.hue = hslColor.hue;
this.saturation = hslColor.saturation;
this.luminosity = hslColor.luminosity;
this.a = hslColor.a;
}
/// <summary>
/// The to rgb string.
/// </summary>
/// <returns>
/// The <see cref="string"/>.
/// </returns>
public string ToRGBString()
{
Color color = this;
return string.Format("R: {0:#0.##} G: {1:#0.##} B: {2:#0.##}", color.R, color.G, color.B);
}
/// <summary>
/// The to string.
/// </summary>
/// <returns>
/// The <see cref="string"/>.
/// </returns>
public override string ToString()
{
return string.Format("H: {0:#0.##} S: {1:#0.##} L: {2:#0.##}", this.Hue, this.Saturation, this.Luminosity);
}
#endregion
#region Methods
/// <summary>
/// The get color component.
/// </summary>
/// <param name="temp1">
/// The temp 1.
/// </param>
/// <param name="temp2">
/// The temp 2.
/// </param>
/// <param name="temp3">
/// The temp 3.
/// </param>
/// <returns>
/// The <see cref="double"/>.
/// </returns>
private static double GetColorComponent(double temp1, double temp2, double temp3)
{
temp3 = MoveIntoRange(temp3);
if (temp3 < 1.0 / 6.0)
{
return temp1 + ((temp2 - temp1) * 6.0 * temp3);
}
if (temp3 < 0.5)
{
return temp2;
}
if (temp3 < 2.0 / 3.0)
{
return temp1 + ((temp2 - temp1) * ((2.0 / 3.0) - temp3) * 6.0);
}
return temp1;
}
/// <summary>
/// The get temp 2.
/// </summary>
/// <param name="hslColor">
/// The hsl color.
/// </param>
/// <returns>
/// The <see cref="double"/>.
/// </returns>
private static double GetTemp2(HSLAColor hslColor)
{
double temp2;
if (hslColor.luminosity <= 0.5)
{
temp2 = hslColor.luminosity * (1.0 + hslColor.saturation);
}
else
{
temp2 = hslColor.luminosity + hslColor.saturation - (hslColor.luminosity * hslColor.saturation);
}
return temp2;
}
/// <summary>
/// The move into range.
/// </summary>
/// <param name="temp3">
/// The temp 3.
/// </param>
/// <returns>
/// The <see cref="double"/>.
/// </returns>
private static double MoveIntoRange(double temp3)
{
if (temp3 < 0.0)
{
temp3 += 1.0;
}
else if (temp3 > 1.0)
{
temp3 -= 1.0;
}
return temp3;
}
/// <summary>
/// The check range.
/// </summary>
/// <param name="value">
/// The value.
/// </param>
/// <returns>
/// The <see cref="double"/>.
/// </returns>
private double CheckRange(double value)
{
if (value < 0.0)
{
value = 0.0;
}
else if (value > 1.0)
{
value = 1.0;
}
return value;
}
#endregion
}
}

109
src/ImageProcessor/Imaging/Colors/RGBAColor.cs

@ -0,0 +1,109 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="RGBAColor.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Imaging.Colors
{
using System.Drawing;
/// <summary>
/// Represents an RGBA (red, green, blue, alpha) color.
/// </summary>
public struct RGBAColor
{
/// <summary>
/// The alpha component.
/// </summary>
public byte A;
/// <summary>
/// The blue component.
/// </summary>
public byte B;
/// <summary>
/// The green component.
/// </summary>
public byte G;
/// <summary>
/// The red component.
/// </summary>
public byte R;
/// <summary>
/// Initializes a new instance of the <see cref="RGBAColor"/> struct.
/// </summary>
/// <param name="red">
/// The red component.
/// </param>
/// <param name="green">
/// The green component.
/// </param>
/// <param name="blue">
/// The blue component.
/// </param>
public RGBAColor(byte red, byte green, byte blue)
{
this.R = red;
this.G = green;
this.B = blue;
this.A = 255;
}
/// <summary>
/// Initializes a new instance of the <see cref="RGBAColor"/> struct.
/// </summary>
/// <param name="red">
/// The red component.
/// </param>
/// <param name="green">
/// The green component.
/// </param>
/// <param name="blue">
/// The blue component.
/// </param>
/// <param name="alpha">
/// The alpha component.
/// </param>
public RGBAColor(byte red, byte green, byte blue, byte alpha)
{
this.R = red;
this.G = green;
this.B = blue;
this.A = alpha;
}
/// <summary>
/// Initializes a new instance of the <see cref="RGBAColor"/> struct.
/// </summary>
/// <param name="color">
/// The <see cref="System.Drawing.Color">color.</see>
/// </param>
public RGBAColor(Color color)
{
this.R = color.R;
this.G = color.G;
this.B = color.B;
this.A = color.A;
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="RGBAColor"/> to a
/// <see cref="System.Drawing.Color"/>.
/// </summary>
/// <param name="rgba">
/// The instance of <see cref="RGBAColor"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="System.Drawing.Color"/>.
/// </returns>
public static implicit operator Color(RGBAColor rgba)
{
return System.Drawing.Color.FromArgb(rgba.A, rgba.R, rgba.G, rgba.B);
}
}
}

256
src/ImageProcessor/Imaging/FastBitmap.cs

@ -0,0 +1,256 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="FastBitmap.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// Allows fast access to <see cref="System.Drawing.Bitmap" />'s pixel data.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Imaging
{
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
/// <summary>
/// Allows fast access to <see cref="System.Drawing.Bitmap"/>'s pixel data.
/// </summary>
public class FastBitmap : IDisposable
{
/// <summary>
/// The bitmap.
/// </summary>
private readonly Bitmap bitmap;
/// <summary>
/// The width of the bitmap.
/// </summary>
private readonly int width;
/// <summary>
/// The height of the bitmap.
/// </summary>
private readonly int height;
/// <summary>
/// The stride width of the bitmap.
/// </summary>
private int stride;
/// <summary>
/// The bitmap data.
/// </summary>
private BitmapData bitmapData;
/// <summary>
/// The pixel buffer for holding pixel data.
/// </summary>
private byte[] pixelBuffer;
/// <summary>
/// The buffer length.
/// </summary>
private int bufferLength;
/// <summary>
/// A value indicating whether this instance of the given entity has been disposed.
/// </summary>
/// <value><see langword="true"/> if this instance has been disposed; otherwise, <see langword="false"/>.</value>
/// <remarks>
/// If the entity is disposed, it must not be disposed a second
/// time. The isDisposed field is set the first time the entity
/// is disposed. If the isDisposed field is true, then the Dispose()
/// method will not dispose again. This help not to prolong the entity's
/// life in the Garbage Collector.
/// </remarks>
private bool isDisposed;
/// <summary>
/// Initializes a new instance of the <see cref="FastBitmap"/> class.
/// </summary>
/// <param name="bitmap">The input bitmap.</param>
public FastBitmap(Bitmap bitmap)
{
this.bitmap = bitmap;
this.width = this.bitmap.Width;
this.height = this.bitmap.Height;
this.LockBitmap();
}
/// <summary>
/// Gets the width, in pixels of the <see cref="System.Drawing.Bitmap"/>.
/// </summary>
public int Width
{
get
{
return this.width;
}
}
/// <summary>
/// Gets the height, in pixels of the <see cref="System.Drawing.Bitmap"/>.
/// </summary>
public int Height
{
get
{
return this.height;
}
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="FastBitmap"/> to a
/// <see cref="System.Drawing.Image"/>.
/// </summary>
/// <param name="fastBitmap">
/// The instance of <see cref="FastBitmap"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="System.Drawing.Image"/>.
/// </returns>
public static implicit operator Image(FastBitmap fastBitmap)
{
return fastBitmap.bitmap;
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="FastBitmap"/> to a
/// <see cref="System.Drawing.Bitmap"/>.
/// </summary>
/// <param name="fastBitmap">
/// The instance of <see cref="FastBitmap"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="System.Drawing.Bitmap"/>.
/// </returns>
public static implicit operator Bitmap(FastBitmap fastBitmap)
{
return fastBitmap.bitmap;
}
/// <summary>
/// Gets the color at the specified pixel of the <see cref="System.Drawing.Bitmap"/>.
/// </summary>
/// <param name="x">The x-coordinate of the pixel to retrieve.</param>
/// <param name="y">The y-coordinate of the pixel to retrieve.</param>
/// <returns>The <see cref="System.Drawing.Color"/> at the given pixel.</returns>
public Color GetPixel(int x, int y)
{
if ((x < 0) || (x >= this.width))
{
throw new ArgumentOutOfRangeException("x", "Value cannot be less than zero or greater than the bitmap width.");
}
if ((y < 0) || (y >= this.height))
{
throw new ArgumentOutOfRangeException("y", "Value cannot be less than zero or greater than the bitmap height.");
}
int position = (x * 4) + (y * this.stride);
byte blue = this.pixelBuffer[position];
byte green = this.pixelBuffer[position + 1];
byte red = this.pixelBuffer[position + 2];
byte alpha = this.pixelBuffer[position + 3];
return Color.FromArgb(alpha, red, green, blue);
}
/// <summary>
/// Sets the color of the specified pixel of the <see cref="System.Drawing.Bitmap"/>.
/// </summary>
/// <param name="x">The x-coordinate of the pixel to set.</param>
/// <param name="y">The y-coordinate of the pixel to set.</param>
/// <param name="color">
/// A <see cref="System.Drawing.Color"/> color structure that represents the
/// color to set the specified pixel.
/// </param>
public void SetPixel(int x, int y, Color color)
{
if ((x < 0) || (x >= this.width))
{
throw new ArgumentOutOfRangeException("x", "Value cannot be less than zero or greater than the bitmap width.");
}
if ((y < 0) || (y >= this.height))
{
throw new ArgumentOutOfRangeException("y", "Value cannot be less than zero or greater than the bitmap height.");
}
int position = (x * 4) + (y * this.stride);
this.pixelBuffer[position] = color.B;
this.pixelBuffer[position + 1] = color.G;
this.pixelBuffer[position + 2] = color.R;
this.pixelBuffer[position + 3] = color.A;
}
/// <summary>
/// Disposes the object and frees resources for the Garbage Collector.
/// </summary>
public void Dispose()
{
this.Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
/// <summary>
/// Disposes the object and frees resources for the Garbage Collector.
/// </summary>
/// <param name="disposing">If true, the object gets disposed.</param>
protected virtual void Dispose(bool disposing)
{
if (this.isDisposed)
{
return;
}
if (disposing)
{
// Dispose of any managed resources here.
this.UnlockBitmap();
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// Note disposing is done.
this.isDisposed = true;
}
/// <summary>
/// Locks the bitmap into system memory.
/// </summary>
private void LockBitmap()
{
Rectangle bounds = new Rectangle(Point.Empty, this.bitmap.Size);
// Lock the bitmap
this.bitmapData = this.bitmap.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
// Copy the bitmap data across to the array for manipulation.
this.stride = this.bitmapData.Stride;
this.bufferLength = this.stride * this.bitmapData.Height;
this.pixelBuffer = new byte[this.bufferLength];
Marshal.Copy(this.bitmapData.Scan0, this.pixelBuffer, 0, this.pixelBuffer.Length);
}
/// <summary>
/// Unlocks the bitmap from system memory.
/// </summary>
private void UnlockBitmap()
{
// Copy the RGB values back to the bitmap and unlock the bitmap.
Marshal.Copy(this.pixelBuffer, 0, this.bitmapData.Scan0, this.bufferLength);
this.bitmap.UnlockBits(this.bitmapData);
this.bitmapData = null;
this.pixelBuffer = null;
}
}
}

93
src/ImageProcessor/Imaging/Filters/ComicMatrixFilter.cs

@ -12,7 +12,6 @@ namespace ImageProcessor.Imaging.Filters
{
#region Using
using System;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
@ -27,23 +26,6 @@ namespace ImageProcessor.Imaging.Filters
/// </summary>
internal class ComicMatrixFilter : MatrixFilterBase
{
/// <summary>
/// Enumerates Argb color channels.
/// </summary>
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Reviewed. Suppression is OK here.")]
private enum ChannelArgb
{
/// <summary>
/// The blue channel
/// </summary>
Blue = 0,
/// <summary>
/// The alpha channel
/// </summary>
Alpha = 3
}
/// <summary>
/// Gets the <see cref="T:System.Drawing.Imaging.ColorMatrix"/> for this filter instance.
/// </summary>
@ -127,7 +109,7 @@ namespace ImageProcessor.Imaging.Filters
}
// Transfer the alpha channel from the mask to the high saturation image.
TransferOneArgbChannelFromOneBitmapToAnother(patternBitmap, lowBitmap, ChannelArgb.Blue, ChannelArgb.Alpha);
ApplyMask(patternBitmap, lowBitmap);
using (Graphics graphics = Graphics.FromImage(newImage))
{
@ -511,7 +493,7 @@ namespace ImageProcessor.Imaging.Filters
}
/// <summary>
/// Transfers a single ARGB channel from one image to another.
/// Applies a mask .
/// </summary>
/// <param name="source">
/// The source.
@ -519,65 +501,38 @@ namespace ImageProcessor.Imaging.Filters
/// <param name="destination">
/// The destination.
/// </param>
/// <param name="sourceChannel">
/// The source channel.
/// </param>
/// <param name="destinationChannel">
/// The destination channel.
/// </param>
private static void TransferOneArgbChannelFromOneBitmapToAnother(Bitmap source, Bitmap destination, ChannelArgb sourceChannel, ChannelArgb destinationChannel)
/// <exception cref="ArgumentException">
/// Thrown if the two images are of different size.
/// </exception>
private static void ApplyMask(Bitmap source, Bitmap destination)
{
if (source.Size != destination.Size)
{
throw new ArgumentException();
}
Rectangle rectangle = new Rectangle(Point.Empty, source.Size);
// Lock the source.
BitmapData bitmapDataSource = source.LockBits(rectangle, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
// Declare an array to hold the bytes of the bitmap.
int bytes = bitmapDataSource.Stride * bitmapDataSource.Height;
// Allocate a buffer for the source image
byte[] sourceRgbValues = new byte[bytes];
// Copy the RGB values into the array.
Marshal.Copy(bitmapDataSource.Scan0, sourceRgbValues, 0, bytes);
// Unlock the source.
source.UnlockBits(bitmapDataSource);
// Lock the destination.
BitmapData bitmapDataDestination = destination.LockBits(rectangle, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
// Allocate a buffer for image
byte[] destinationRgbValues = new byte[bytes];
// Copy the RGB values into the array.
Marshal.Copy(bitmapDataDestination.Scan0, destinationRgbValues, 0, bytes);
int s = (int)sourceChannel;
int d = (int)destinationChannel;
for (int i = rectangle.Height * rectangle.Width; i > 0; i--)
using (FastBitmap sourceBitmap = new FastBitmap(source))
{
// Copy the alpha values across.
if (destinationRgbValues[d] != 0)
using (FastBitmap destinationBitmap = new FastBitmap(destination))
{
destinationRgbValues[d] = sourceRgbValues[s];
}
int width = source.Width;
int height = source.Height;
d += 4;
s += 4;
}
// Copy the RGB values back to the bitmap
Marshal.Copy(destinationRgbValues, 0, bitmapDataDestination.Scan0, bytes);
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
Color sourceColor = sourceBitmap.GetPixel(i, j);
Color destinationColor = destinationBitmap.GetPixel(i, j);
// Unlock bits the destination.
destination.UnlockBits(bitmapDataDestination);
if (destinationColor.A != 0)
{
destinationBitmap.SetPixel(i, j, Color.FromArgb(sourceColor.B, destinationColor.R, destinationColor.G, destinationColor.B));
}
}
}
}
}
}
}
}

2
src/ImageProcessor/Processors/Alpha.cs

@ -31,7 +31,7 @@ namespace ImageProcessor.Processors
}
/// <summary>
/// Gets or sets DynamicParameter.
/// Gets or sets the dynamic parameter.
/// </summary>
public dynamic DynamicParameter
{

96
src/ImageProcessor/Processors/Hue.cs

@ -0,0 +1,96 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Hue.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.Collections.Generic;
using System.Drawing;
using ImageProcessor.Common.Exceptions;
using ImageProcessor.Imaging;
using ImageProcessor.Imaging.Colors;
/// <summary>
/// Encapsulates methods to rotate the hue component of an image.
/// </summary>
public class Hue : IGraphicsProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="Hue"/> class.
/// </summary>
public Hue()
{
this.Settings = new Dictionary<string, string>();
}
/// <summary>
/// Gets or sets the dynamic parameter.
/// </summary>
public dynamic DynamicParameter { get; set; }
/// <summary>
/// Gets or sets any additional settings required by the processor.
/// </summary>
public Dictionary<string, string> Settings { get; set; }
/// <summary>
/// Processes the image.
/// </summary>
/// <param name="factory">
/// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class containing
/// the image to process.
/// </param>
/// <returns>
/// The processed image from the current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class.
/// </returns>
public Image ProcessImage(ImageFactory factory)
{
Bitmap newImage = null;
Image image = factory.Image;
try
{
int degrees = this.DynamicParameter;
int width = image.Width;
int height = image.Height;
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 hsl = new HSLAColor(fastBitmap.GetPixel(i, j));
hsl.Hue = (hsl.Hue + (degrees / 360f)) % 1;
//hsl.Hue = (degrees / 360f);
fastBitmap.SetPixel(i, j, hsl);
}
}
}
image.Dispose();
image = newImage;
}
catch (Exception ex)
{
if (newImage != null)
{
newImage.Dispose();
}
throw new ImageProcessingException("Error processing image with " + this.GetType().Name, ex);
}
return image;
}
}
}

28
src/ImageProcessorConsole/Program.cs

@ -17,6 +17,7 @@ namespace ImageProcessorConsole
using System.IO;
using System.Linq;
using ImageProcessor;
using ImageProcessor.Imaging;
using ImageProcessor.Plugins.Cair;
using ImageProcessor.Plugins.Cair.Imaging;
@ -50,7 +51,15 @@ namespace ImageProcessorConsole
{
byte[] photoBytes = File.ReadAllBytes(fileInfo.FullName);
Console.WriteLine("Processing: " + fileInfo.Name);
//Color color = Color.Green;
//HSLAColor hslaColor = HSLAColor.FromRGBA(color);
//Console.WriteLine("H:" + hslaColor.H + " S:" + hslaColor.S + " L:" + hslaColor.L);
//Color color2 = HSLAColor.ToRGBA(hslaColor);
//Console.WriteLine("Color Out: " + "R:" + color2.R + " G:" + color2.G + " B:" + color2.B + " A:" + color2.A);
//Console.WriteLine(color2 == Color.Green);
//Console.WriteLine("Processing: " + fileInfo.Name);
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
@ -60,19 +69,20 @@ namespace ImageProcessorConsole
{
using (ImageFactory imageFactory = new ImageFactory(true))
{
Size size = new Size(800, 0);
Size size = new Size(448, 0);
ContentAwareResizeLayer layer = new ContentAwareResizeLayer(size)
{
ConvolutionType = ConvolutionType.Sobel
};
//ContentAwareResizeLayer layer = new ContentAwareResizeLayer(size)
//{
// ConvolutionType = ConvolutionType.Sobel
//};
// Load, resize, set the format and quality and save an image.
imageFactory.Load(inStream)
//.BackgroundColor(Color.White)
//.Resize(new Size((int)(size.Width * 1.1), 0))
.ContentAwareResize(layer)
//.Constrain(size)
//.ContentAwareResize(layer)
.Constrain(size)
.Hue(180)
.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name)));
stopwatch.Stop();
@ -81,6 +91,8 @@ namespace ImageProcessorConsole
Console.WriteLine("Processed: " + fileInfo.Name + " in " + stopwatch.ElapsedMilliseconds + "ms");
}
Console.ReadLine();
}
public static IEnumerable<FileInfo> GetFilesByExtensions(DirectoryInfo dir, params string[] extensions)

0
src/ImageProcessorConsole/images/input/Image with gaps.jpg.REMOVED.git-id → src/ImageProcessorConsole/images/input/1aaa.jpg.REMOVED.git-id

1
src/ImageProcessorConsole/images/input/IC580196.jpg.REMOVED.git-id

@ -0,0 +1 @@
9ab3fa52dd238ee4caffb47c82929f4079dc38d3

BIN
src/ImageProcessorConsole/images/input/Turtle.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
src/ImageProcessorConsole/images/input/sample1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

1
src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id

@ -1 +0,0 @@
e41022eb5fe724ba5fe2b7aeda29a1f4b6878484

BIN
src/ImageProcessorConsole/images/output/1aaa.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
src/ImageProcessorConsole/images/output/2006-citybus.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

1
src/ImageProcessorConsole/images/output/2006-citybus.jpg.REMOVED.git-id

@ -1 +0,0 @@
c6cb11afaf9fdb9181772246e5c873d8f7d1b99c

2
src/ImageProcessorConsole/images/output/2008.jpg.REMOVED.git-id

@ -1 +1 @@
10b48cac44776a023df7585ba2c68c3f51b0f803
73753ca19a0818ee4a88b6e9e0eb85ca17624269

BIN
src/ImageProcessorConsole/images/output/2012-citybus.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

1
src/ImageProcessorConsole/images/output/2012-citybus.jpg.REMOVED.git-id

@ -1 +0,0 @@
e631eb3491496bb83f99cd41a752f79c9d7f6830

BIN
src/ImageProcessorConsole/images/output/4.sm.webp

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

2
src/ImageProcessorConsole/images/output/Arc-de-Triomphe-France.jpg.REMOVED.git-id

@ -1 +1 @@
782056919992bb7e453eeee5d9c0034e03b57506
dff097307936637d1c43f82ca28f4582c9810de7

BIN
src/ImageProcessorConsole/images/output/IC580196.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

1
src/ImageProcessorConsole/images/output/Image with gaps.jpg.REMOVED.git-id

@ -1 +0,0 @@
1d9ded0201edcd248140b4ec02f69ccdb4b539e5

1
src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id

@ -1 +0,0 @@
f5681324d193a42492647f4952057c2b72026096

BIN
src/ImageProcessorConsole/images/output/Turtle.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
src/ImageProcessorConsole/images/output/arc_de_triomphe_paris_france.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

1
src/ImageProcessorConsole/images/output/arc_de_triomphe_paris_france.jpg.REMOVED.git-id

@ -1 +0,0 @@
2880457cc09cd2897b5f9f377807ec22f8f83013

BIN
src/ImageProcessorConsole/images/output/circle.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

1
src/ImageProcessorConsole/images/output/monster.png.REMOVED.git-id

@ -1 +0,0 @@
d8d3354b684cad79d9a46f92ed3a58747a808ad1

BIN
src/ImageProcessorConsole/images/output/mountain.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

1
src/ImageProcessorConsole/images/output/mountain.jpg.REMOVED.git-id

@ -1 +0,0 @@
34dcced6c7c3e4dd6fae239eba8eddef6234028d

1
src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id

@ -1 +0,0 @@
b65d9e937cad7ddd02ff0d01a3be2f09c55e63e8

BIN
src/ImageProcessorConsole/images/output/night-bridge.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

BIN
src/ImageProcessorConsole/images/output/rotate.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

1
src/ImageProcessorConsole/images/output/rotate.jpg.REMOVED.git-id

@ -1 +0,0 @@
de6754762f7705f9109ea364f42ca128e454e853

BIN
src/ImageProcessorConsole/images/output/sample1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
src/ImageProcessorConsole/images/output/shutterstock_19173982_Arc_de_triomphe-square1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

1
src/ImageProcessorConsole/images/output/shutterstock_19173982_Arc_de_triomphe-square1.jpg.REMOVED.git-id

@ -1 +0,0 @@
24db72130626e81b9a4262c891dd28e6d97e5a96

BIN
src/ImageProcessorConsole/images/output/test.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

1
src/ImageProcessorConsole/images/output/test.jpg.REMOVED.git-id

@ -1 +0,0 @@
4885438f0b97e3aae59d6e214b5ec455358ae225

BIN
src/ImageProcessorConsole/images/output/test.webp

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

BIN
src/ImageProcessorConsole/images/output/tower.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

1
src/ImageProcessorConsole/images/output/tower.jpg.REMOVED.git-id

@ -1 +0,0 @@
2d5b165c27545a3860d8a6b35f8ac4438f57593a
Loading…
Cancel
Save