Browse Source

Initial addition of hue adjustment processor

Former-commit-id: 6bae314ea0932804874ab3bee1cade7d1dd3d0ee
af/merge-core
James South 12 years ago
parent
commit
a7afcdc59c
  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. 3
      src/ImageProcessorConsole/images/input/Turtle.jpg
  14. 3
      src/ImageProcessorConsole/images/input/sample1.jpg
  15. 1
      src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id
  16. 3
      src/ImageProcessorConsole/images/output/1aaa.jpg
  17. 3
      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. 3
      src/ImageProcessorConsole/images/output/2012-citybus.jpg
  21. 1
      src/ImageProcessorConsole/images/output/2012-citybus.jpg.REMOVED.git-id
  22. 3
      src/ImageProcessorConsole/images/output/4.sm.webp
  23. 2
      src/ImageProcessorConsole/images/output/Arc-de-Triomphe-France.jpg.REMOVED.git-id
  24. 3
      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. 3
      src/ImageProcessorConsole/images/output/Turtle.jpg
  28. 3
      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. 3
      src/ImageProcessorConsole/images/output/circle.png
  31. 1
      src/ImageProcessorConsole/images/output/monster.png.REMOVED.git-id
  32. 3
      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. 3
      src/ImageProcessorConsole/images/output/night-bridge.jpg
  36. 3
      src/ImageProcessorConsole/images/output/rotate.jpg
  37. 1
      src/ImageProcessorConsole/images/output/rotate.jpg.REMOVED.git-id
  38. 3
      src/ImageProcessorConsole/images/output/sample1.jpg
  39. 3
      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. 3
      src/ImageProcessorConsole/images/output/test.jpg
  42. 1
      src/ImageProcessorConsole/images/output/test.jpg.REMOVED.git-id
  43. 3
      src/ImageProcessorConsole/images/output/test.webp
  44. 3
      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

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9e5c576b0c5e743cfd498b110305268ecbae63c62061ba6c7eb8e060728191f1
size 55126

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6b2012b2eda13a531645c287c254ae5de0e9070368cb4bc806f48314e0464ccd
size 33850

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

@ -1 +0,0 @@
e41022eb5fe724ba5fe2b7aeda29a1f4b6878484

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d14cef359c56dd4c96a32bcd481f850a4fd92456f10924c489e40d11b6dec07f
size 30595

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7b064358a5ea1ab9b955b003cfedad5766f7fbe4ed697ee5c78e99ab3da55367
size 41725

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

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:467ba90a3e6e12846a9688e23f6b88720a7122b5f56bd2941f593093845f432e
size 40091

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

@ -1 +0,0 @@
e631eb3491496bb83f99cd41a752f79c9d7f6830

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

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bc9ccd29734ed06d2916389cc363955924f4bbb200fea91c113ae2b9334eca1f
size 12162

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

@ -1 +1 @@
782056919992bb7e453eeee5d9c0034e03b57506
dff097307936637d1c43f82ca28f4582c9810de7

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e1d0a6823f6e169bddf04f53c6b9658dadfa5ec044d097521e2ad987c9476a32
size 40336

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

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ac5e652d9164404b39a652a6835edfdd93407edf2dc5d4f5f177f304f3250251
size 49160

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a8b8013175ece5b73dc5f8d20704c6b01b5de1649b0d553f1187d6ab199f0f5d
size 35513

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

@ -1 +0,0 @@
2880457cc09cd2897b5f9f377807ec22f8f83013

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

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:be35a2ed96081bdb3f2b6da83036554509f6b53b6a145f2ae5de91d381e63fc0
size 5001

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

@ -1 +0,0 @@
d8d3354b684cad79d9a46f92ed3a58747a808ad1

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a1a2018c1936a90b0d61b2a007353cbdec7b322d7407413c64cb02ccea2e203c
size 46923

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

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

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7929c57d7a5711d6fec185afc0063ad1a3fbd4e281067a1b36f18682662752be
size 56360

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3a74078fdeb9e790d1bf8352dfdbefded009f167666832fc9a84b51537730a7f
size 49894

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

@ -1 +0,0 @@
de6754762f7705f9109ea364f42ca128e454e853

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b86a79be3c4c94ffb790b9bc8c60e294447c53bc05e308d14dd167df2c257ff9
size 39071

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5309055af67cbd35a21a2ad178bc0e7ec92c971329bdc2b3da4800d4dc27822f
size 41847

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

@ -1 +0,0 @@
24db72130626e81b9a4262c891dd28e6d97e5a96

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9638658680655e1c42b84f06728c8a0faa5ff82dbc1029118c93ada0553e2e7f
size 54357

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

@ -1 +0,0 @@
4885438f0b97e3aae59d6e214b5ec455358ae225

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

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b41b4fe144f9d3eaee706b516021efc7abc598f17655d9592866963bfa62f3ad
size 5590

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4d1f4409d53b75a5b650cd45356f70b3e05ad554aaf54211a810e7ca17ec21f1
size 47276

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

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