Browse Source

Adding YCbCr (not correct yet)

Former-commit-id: 3e72f3c0fd48b9f990701ad65001b8f71849673c
pull/17/head
James South 12 years ago
parent
commit
9fdc7c768d
  1. 76
      src/ImageProcessor.UnitTests/Imaging/ColorUnitTests.cs
  2. 1
      src/ImageProcessor/ImageProcessor.csproj
  3. 86
      src/ImageProcessor/Imaging/Colors/HSLAColor.cs
  4. 163
      src/ImageProcessor/Imaging/Colors/YCbCrColor.cs
  5. 2
      src/ImageProcessor/Processors/Hue.cs

76
src/ImageProcessor.UnitTests/Imaging/ColorUnitTests.cs

@ -10,6 +10,7 @@
namespace ImageProcessor.UnitTests.Imaging
{
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using ImageProcessor.Imaging.Colors;
using NUnit.Framework;
@ -45,17 +46,78 @@ namespace ImageProcessor.UnitTests.Imaging
}
/// <summary>
/// Test conversion to and from a HSLA color.
/// Test conversion to and from a <see cref="HslaColor"/>.
/// </summary>
/// <param name="expected">
/// The expected output.
/// </param>
[Test]
public void TestHSLAConversion()
[TestCase("#FEFFFE")]
[TestCase("#000000")]
[TestCase("#CCFF33")]
[TestCase("#990000")]
[TestCase("#5C955C")]
[TestCase("#5C5C95")]
[TestCase("#3F3F66")]
[TestCase("#FFFFBB")]
[TestCase("#FF002B")]
[TestCase("#00ABFF")]
public void TestHslaConversion(string expected)
{
const string Hex = "#FEFFFE";
Color color = ColorTranslator.FromHtml(Hex);
Color color = ColorTranslator.FromHtml(expected);
HslaColor hslaColor = HslaColor.FromColor(color);
string outPut = ColorTranslator.ToHtml(hslaColor);
Assert.AreEqual(Hex, outPut);
string result = ColorTranslator.ToHtml(hslaColor);
Assert.AreEqual(expected, result);
}
/// <summary>
/// Test conversion to and from a <see cref="RgbaColor"/>.
/// </summary>
/// <param name="expected">
/// The expected output.
/// </param>
[Test]
[TestCase("#FEFFFE")]
[TestCase("#000000")]
[TestCase("#CCFF33")]
[TestCase("#990000")]
[TestCase("#5C955C")]
[TestCase("#5C5C95")]
[TestCase("#3F3F66")]
[TestCase("#FFFFBB")]
[TestCase("#FF002B")]
[TestCase("#00ABFF")]
public void TestRgbaConversion(string expected)
{
Color color = ColorTranslator.FromHtml(expected);
RgbaColor rgbaColor = RgbaColor.FromColor(color);
string result = ColorTranslator.ToHtml(rgbaColor);
Assert.AreEqual(expected, result);
}
///// <summary>
///// Test conversion to and from a <see cref="RgbaColor"/>.
///// </summary>
///// <param name="expected">
///// The expected output.
///// </param>
//[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Reviewed. Suppression is OK here."),Test]
//[TestCase("#FEFFFE")]
//[TestCase("#000000")]
//[TestCase("#CCFF33")]
//[TestCase("#990000")]
//[TestCase("#5C955C")]
//[TestCase("#5C5C95")]
//[TestCase("#3F3F66")]
//[TestCase("#FFFFBB")]
//[TestCase("#FF002B")]
//[TestCase("#00ABFF")]
//public void TestYCbCrConversion(string expected)
//{
// Color color = ColorTranslator.FromHtml(expected);
// YCbCrColor yCbCrColor = YCbCrColor.FromColor(color);
// string result = ColorTranslator.ToHtml(yCbCrColor);
// Assert.AreEqual(expected, result);
//}
}
}

1
src/ImageProcessor/ImageProcessor.csproj

@ -72,6 +72,7 @@
<Compile Include="Configuration\NativeMethods.cs" />
<Compile Include="Imaging\Colors\HslaColor.cs" />
<Compile Include="Imaging\Colors\RgbaColor.cs" />
<Compile Include="Imaging\Colors\YCbCrColor.cs" />
<Compile Include="Imaging\FastBitmap.cs" />
<Compile Include="Imaging\Formats\GifInfo.cs" />
<Compile Include="Common\Extensions\IntegerExtensions.cs" />

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

@ -27,22 +27,22 @@ namespace ImageProcessor.Imaging.Colors
/// <summary>
/// The hue component.
/// </summary>
private readonly double h;
private readonly float h;
/// <summary>
/// The luminosity component.
/// </summary>
private readonly double l;
private readonly float l;
/// <summary>
/// The saturation component.
/// </summary>
private readonly double s;
private readonly float s;
/// <summary>
/// The alpha component.
/// </summary>
private readonly double a;
private readonly float a;
/// <summary>
/// Initializes a new instance of the <see cref="HslaColor"/> struct.
@ -59,7 +59,7 @@ namespace ImageProcessor.Imaging.Colors
/// <param name="alpha">
/// The alpha component.
/// </param>
private HslaColor(double hue, double saturation, double luminosity, double alpha)
private HslaColor(float hue, float saturation, float luminosity, float alpha)
{
this.h = Clamp(hue);
this.s = Clamp(saturation);
@ -85,7 +85,7 @@ namespace ImageProcessor.Imaging.Colors
/// <summary>
/// Gets the hue component.
/// </summary>
public double H
public float H
{
get
{
@ -96,7 +96,7 @@ namespace ImageProcessor.Imaging.Colors
/// <summary>
/// Gets the luminosity component.
/// </summary>
public double L
public float L
{
get
{
@ -107,7 +107,7 @@ namespace ImageProcessor.Imaging.Colors
/// <summary>
/// Gets the saturation component.
/// </summary>
public double S
public float S
{
get
{
@ -118,7 +118,7 @@ namespace ImageProcessor.Imaging.Colors
/// <summary>
/// Gets the alpha component.
/// </summary>
public double A
public float A
{
get
{
@ -127,7 +127,7 @@ namespace ImageProcessor.Imaging.Colors
}
/// <summary>
/// Creates a <see cref="HslaColor"/> structure from the three 64-bit HSLA
/// Creates a <see cref="HslaColor"/> structure from the three 32-bit HSLA
/// components (hue, saturation, and luminosity) values.
/// </summary>
/// <param name="hue">
@ -142,13 +142,13 @@ namespace ImageProcessor.Imaging.Colors
/// <returns>
/// The <see cref="HslaColor"/>.
/// </returns>
public static HslaColor FromHslaColor(double hue, double saturation, double luminosity)
public static HslaColor FromHslaColor(float hue, float saturation, float luminosity)
{
return new HslaColor(hue, saturation, luminosity, 1.0);
return new HslaColor(hue, saturation, luminosity, 1.0f);
}
/// <summary>
/// Creates a <see cref="HslaColor"/> structure from the four 64-bit HSLA
/// Creates a <see cref="HslaColor"/> structure from the four 32-bit HSLA
/// components (hue, saturation, luminosity, and alpha) values.
/// </summary>
/// <param name="hue">
@ -166,7 +166,7 @@ namespace ImageProcessor.Imaging.Colors
/// <returns>
/// The <see cref="HslaColor"/>.
/// </returns>
public static HslaColor FromHslaColor(double hue, double saturation, double luminosity, double alpha)
public static HslaColor FromHslaColor(float hue, float saturation, float luminosity, float alpha)
{
return new HslaColor(hue, saturation, luminosity, alpha);
}
@ -198,7 +198,7 @@ namespace ImageProcessor.Imaging.Colors
public static implicit operator HslaColor(Color color)
{
HslaColor hslColor = new HslaColor(
color.GetHue() / 360.0,
color.GetHue() / 360.0f,
color.GetSaturation(),
color.GetBrightness(),
color.A / 255f);
@ -220,7 +220,7 @@ namespace ImageProcessor.Imaging.Colors
{
Color color = rgbaColor;
HslaColor hslColor = new HslaColor(
color.GetHue() / 360.0,
color.GetHue() / 360.0f,
color.GetSaturation(),
color.GetBrightness(),
color.A / 255f);
@ -240,7 +240,7 @@ namespace ImageProcessor.Imaging.Colors
/// </returns>
public static implicit operator Color(HslaColor hslaColor)
{
double r = 0, g = 0, b = 0;
float r = 0, g = 0, b = 0;
if (Math.Abs(hslaColor.l - 0) > .0001)
{
if (Math.Abs(hslaColor.s - 0) <= .0001)
@ -249,12 +249,12 @@ namespace ImageProcessor.Imaging.Colors
}
else
{
double temp2 = GetTemp2(hslaColor);
double temp1 = (2.0 * hslaColor.l) - temp2;
float temp2 = GetTemp2(hslaColor);
float temp1 = (2.0f * hslaColor.l) - temp2;
r = GetColorComponent(temp1, temp2, hslaColor.h + (1.0 / 3.0));
r = GetColorComponent(temp1, temp2, hslaColor.h + (1.0f / 3.0f));
g = GetColorComponent(temp1, temp2, hslaColor.h);
b = GetColorComponent(temp1, temp2, hslaColor.h - (1.0 / 3.0));
b = GetColorComponent(temp1, temp2, hslaColor.h - (1.0f / 3.0f));
}
}
@ -277,7 +277,7 @@ namespace ImageProcessor.Imaging.Colors
/// </returns>
public static implicit operator RgbaColor(HslaColor hslaColor)
{
double r = 0, g = 0, b = 0;
float r = 0, g = 0, b = 0;
if (Math.Abs(hslaColor.l - 0) > .0001)
{
if (Math.Abs(hslaColor.s - 0) <= .0001)
@ -286,12 +286,12 @@ namespace ImageProcessor.Imaging.Colors
}
else
{
double temp2 = GetTemp2(hslaColor);
double temp1 = (2.0 * hslaColor.l) - temp2;
float temp2 = GetTemp2(hslaColor);
float temp1 = (2.0f * hslaColor.l) - temp2;
r = GetColorComponent(temp1, temp2, hslaColor.h + (1.0 / 3.0));
r = GetColorComponent(temp1, temp2, hslaColor.h + (1.0f / 3.0f));
g = GetColorComponent(temp1, temp2, hslaColor.h);
b = GetColorComponent(temp1, temp2, hslaColor.h - (1.0 / 3.0));
b = GetColorComponent(temp1, temp2, hslaColor.h - (1.0f / 3.0f));
}
}
@ -363,14 +363,14 @@ namespace ImageProcessor.Imaging.Colors
/// The temp 3.
/// </param>
/// <returns>
/// The <see cref="double"/>.
/// The <see cref="float"/>.
/// </returns>
private static double GetColorComponent(double temp1, double temp2, double temp3)
private static float GetColorComponent(float temp1, float temp2, float temp3)
{
temp3 = MoveIntoRange(temp3);
if (temp3 < 1.0 / 6.0)
{
return temp1 + ((temp2 - temp1) * 6.0 * temp3);
return temp1 + ((temp2 - temp1) * 6.0f * temp3);
}
if (temp3 < 0.5)
@ -380,7 +380,7 @@ namespace ImageProcessor.Imaging.Colors
if (temp3 < 2.0 / 3.0)
{
return temp1 + ((temp2 - temp1) * ((2.0 / 3.0) - temp3) * 6.0);
return temp1 + ((temp2 - temp1) * ((2.0f / 3.0f) - temp3) * 6.0f);
}
return temp1;
@ -393,14 +393,14 @@ namespace ImageProcessor.Imaging.Colors
/// The <see cref="HslaColor"/> color.
/// </param>
/// <returns>
/// The <see cref="double"/>.
/// The <see cref="float"/>.
/// </returns>
private static double GetTemp2(HslaColor hslColor)
private static float GetTemp2(HslaColor hslColor)
{
double temp2;
float temp2;
if (hslColor.l <= 0.5)
{
temp2 = hslColor.l * (1.0 + hslColor.s);
temp2 = hslColor.l * (1.0f + hslColor.s);
}
else
{
@ -417,17 +417,17 @@ namespace ImageProcessor.Imaging.Colors
/// The temp 3.
/// </param>
/// <returns>
/// The <see cref="double"/>.
/// The <see cref="float"/>.
/// </returns>
private static double MoveIntoRange(double temp3)
private static float MoveIntoRange(float temp3)
{
if (temp3 < 0.0)
{
temp3 += 1.0;
temp3 += 1.0f;
}
else if (temp3 > 1.0)
{
temp3 -= 1.0;
temp3 -= 1.0f;
}
return temp3;
@ -440,17 +440,17 @@ namespace ImageProcessor.Imaging.Colors
/// The value to check.
/// </param>
/// <returns>
/// The sanitized <see cref="double"/>.
/// The sanitized <see cref="float"/>.
/// </returns>
private static double Clamp(double value)
private static float Clamp(float value)
{
if (value < 0.0)
{
value = 0.0;
value = 0.0f;
}
else if (value > 1.0)
{
value = 1.0;
value = 1.0f;
}
return value;
@ -464,7 +464,7 @@ namespace ImageProcessor.Imaging.Colors
/// </returns>
private bool IsEmpty()
{
const double Epsilon = .0001;
const float Epsilon = .0001f;
return Math.Abs(this.h - 0) <= Epsilon && Math.Abs(this.s - 0) <= Epsilon &&
Math.Abs(this.l - 0) <= Epsilon && Math.Abs(this.a - 0) <= Epsilon;
}

163
src/ImageProcessor/Imaging/Colors/YCbCrColor.cs

@ -0,0 +1,163 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="YCbCrColor.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// Represents an YCbCr (luminance, chroma, chroma) color used in digital imaging systems.
// <see href="http://en.wikipedia.org/wiki/YCbCr" />
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Imaging.Colors
{
using System;
using System.Drawing;
using ImageProcessor.Common.Extensions;
/// <summary>
/// Represents an YCbCr (luminance, chroma, chroma) color used in digital imaging systems.
/// <see href="http://en.wikipedia.org/wiki/YCbCr"/>
/// </summary>
public struct YCbCrColor
{
/// <summary>
/// Represents a <see cref="YCbCrColor"/> that is null.
/// </summary>
public static readonly YCbCrColor Empty = new YCbCrColor();
/// <summary>
/// The y luminance component.
/// </summary>
private readonly float y;
/// <summary>
/// The u chroma component.
/// </summary>
private readonly float cb;
/// <summary>
/// The v chroma component.
/// </summary>
private readonly float cr;
/// <summary>
/// Initializes a new instance of the <see cref="YCbCrColor"/> struct.
/// </summary>
/// <param name="y">The y luminance component.</param>
/// <param name="cb">The u chroma component.</param>
/// <param name="cr">The v chroma component.</param>
private YCbCrColor(float y, float cb, float cr)
{
this.y = y; //Math.Max(0.0f, Math.Min(1.0f, y));
this.cb = cb; //Math.Max(-0.5f, Math.Min(0.5f, cb));
this.cr = cr; //Math.Max(-0.5f, Math.Min(0.5f, cr));
}
/// <summary>
/// Gets the Y luminance component.
/// </summary>
public float Y
{
get
{
return this.y;
}
}
/// <summary>
/// Gets the U chroma component.
/// </summary>
public float Cb
{
get
{
return this.y;
}
}
/// <summary>
/// Gets the V chroma component.
/// </summary>
public float Cr
{
get
{
return this.y;
}
}
/// <summary>
/// Creates a <see cref="YCbCrColor"/> structure from the three 32-bit YCbCr
/// components (luminance, chroma, and chroma) values.
/// </summary>
/// <param name="y">The y luminance component.</param>
/// <param name="cb">The u chroma component.</param>
/// <param name="cr">The v chroma component.</param>
/// <returns>
/// The <see cref="YCbCrColor"/>.
/// </returns>
public static YCbCrColor FromYCbCr(float y, float cb, float cr)
{
return new YCbCrColor(y, cb, cr);
}
/// <summary>
/// Creates a <see cref="YCbCrColor"/> structure from the specified <see cref="System.Drawing.Color"/> structure
/// </summary>
/// <param name="color">
/// The <see cref="System.Drawing.Color"/> from which to create the new <see cref="YCbCrColor"/>.
/// </param>
/// <returns>
/// The <see cref="YCbCrColor"/>.
/// </returns>
public static YCbCrColor FromColor(Color color)
{
float r = color.R;
float g = color.G;
float b = color.B;
float y = (float)((0.299 * r) + (0.587 * g) + (0.114 * b));
float cb = 128 - (float)((-0.168736 * r) - (0.331264 * g) + (0.5 * b));
float cr = 128 + (float)((0.5 * r) - (0.418688 * g) - (0.081312 * b));
return new YCbCrColor(y, cb, cr);
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="System.Drawing.Color"/> to a
/// <see cref="YCbCrColor"/>.
/// </summary>
/// <param name="color">
/// The instance of <see cref="System.Drawing.Color"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="YCbCrColor"/>.
/// </returns>
public static implicit operator YCbCrColor(Color color)
{
return FromColor(color);
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="YCbCrColor"/> to a
/// <see cref="System.Drawing.Color"/>.
/// </summary>
/// <param name="ycbcr">
/// The instance of <see cref="YCbCrColor"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="System.Drawing.Color"/>.
/// </returns>
public static implicit operator Color(YCbCrColor ycbcr)
{
byte r = Convert.ToInt32(ycbcr.Y + (1.402 * (ycbcr.Cr - 128))).ToByte();
byte g = Convert.ToInt32(ycbcr.Y - (0.34414 * (ycbcr.Cb - 128)) - (0.71414 * (ycbcr.Cr - 128))).ToByte();
byte b = Convert.ToInt32(ycbcr.Y + (1.772 * (ycbcr.Cb - 128))).ToByte();
return Color.FromArgb(255, r, g, b);
}
}
}

2
src/ImageProcessor/Processors/Hue.cs

@ -70,7 +70,7 @@ namespace ImageProcessor.Processors
for (int j = 0; j < height; j++)
{
HslaColor original = HslaColor.FromColor(fastBitmap.GetPixel(i, j));
HslaColor altered = HslaColor.FromHslaColor(degrees / 360D, original.S, original.L, original.A);
HslaColor altered = HslaColor.FromHslaColor(degrees / 360f, original.S, original.L, original.A);
fastBitmap.SetPixel(i, j, altered);
}
}

Loading…
Cancel
Save