Browse Source

Fixing YcbCr

Former-commit-id: 940697fd8a7d4889a263209975a1043d5e24f125
pull/17/head
James South 12 years ago
parent
commit
41d049a178
  1. 78
      src/ImageProcessor.UnitTests/Imaging/ColorUnitTests.cs
  2. 4
      src/ImageProcessor/Common/Extensions/DoubleExtensions.cs
  3. 75
      src/ImageProcessor/Imaging/Colors/HSLAColor.cs
  4. 42
      src/ImageProcessor/Imaging/Colors/RGBAColor.cs
  5. 163
      src/ImageProcessor/Imaging/Colors/YCbCrColor.cs

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

@ -25,7 +25,7 @@ namespace ImageProcessor.UnitTests.Imaging
/// Tests the <see cref="RgbaColor"/> struct equality operators.
/// </summary>
[Test]
public void TestRGBAEquality()
public void TestRgbaEquality()
{
RgbaColor first = RgbaColor.FromColor(Color.White);
RgbaColor second = RgbaColor.FromColor(Color.White);
@ -34,10 +34,10 @@ namespace ImageProcessor.UnitTests.Imaging
}
/// <summary>
/// Tests the <see cref="RgbaColor"/> struct equality operators.
/// Tests the <see cref="HslaColor"/> struct equality operators.
/// </summary>
[Test]
public void TestHSLAEquality()
public void TestHslaEquality()
{
HslaColor first = HslaColor.FromColor(Color.White);
HslaColor second = HslaColor.FromColor(Color.White);
@ -45,6 +45,18 @@ namespace ImageProcessor.UnitTests.Imaging
Assert.AreEqual(first, second);
}
/// <summary>
/// Tests the <see cref="YCbCrColor"/> struct equality operators.
/// </summary>
[Test]
public void TestYCbCrEquality()
{
YCbCrColor first = YCbCrColor.FromColor(Color.White);
YCbCrColor second = YCbCrColor.FromColor(Color.White);
Assert.AreEqual(first, second);
}
/// <summary>
/// Test conversion to and from a <see cref="HslaColor"/>.
/// </summary>
@ -52,9 +64,13 @@ namespace ImageProcessor.UnitTests.Imaging
/// The expected output.
/// </param>
[Test]
[TestCase("#FFFFFF")]
[TestCase("#FEFFFE")]
[TestCase("#F0F8FF")]
[TestCase("#000000")]
[TestCase("#CCFF33")]
[TestCase("#00FF00")]
[TestCase("#FF00FF")]
[TestCase("#990000")]
[TestCase("#5C955C")]
[TestCase("#5C5C95")]
@ -77,9 +93,13 @@ namespace ImageProcessor.UnitTests.Imaging
/// The expected output.
/// </param>
[Test]
[TestCase("#FFFFFF")]
[TestCase("#FEFFFE")]
[TestCase("#F0F8FF")]
[TestCase("#000000")]
[TestCase("#CCFF33")]
[TestCase("#00FF00")]
[TestCase("#FF00FF")]
[TestCase("#990000")]
[TestCase("#5C955C")]
[TestCase("#5C5C95")]
@ -95,29 +115,33 @@ namespace ImageProcessor.UnitTests.Imaging
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);
//}
/// <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("#FFFFFF")]
[TestCase("#FEFFFE")]
[TestCase("#F0F8FF")]
[TestCase("#000000")]
[TestCase("#CCFF33")]
[TestCase("#00FF00")]
[TestCase("#FF00FF")]
[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);
}
}
}

4
src/ImageProcessor/Common/Extensions/DoubleExtensions.cs

@ -10,6 +10,8 @@
namespace ImageProcessor.Common.Extensions
{
using System;
/// <summary>
/// Encapsulates a series of time saving extension methods to the <see cref="T:System.Double"/> class.
/// </summary>
@ -30,7 +32,7 @@ namespace ImageProcessor.Common.Extensions
/// </returns>
public static byte ToByte(this double d)
{
return (byte)((d > byte.MaxValue) ? byte.MaxValue : ((d < byte.MinValue) ? byte.MinValue : d));
return Convert.ToByte(Math.Max(0.0d, Math.Min(255d, d))); // ((d > byte.MaxValue) ? byte.MaxValue : ((d < byte.MinValue) ? byte.MinValue : d));
}
}
}

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

@ -84,6 +84,7 @@ namespace ImageProcessor.Imaging.Colors
/// <summary>
/// Gets the hue component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float H
{
@ -95,6 +96,7 @@ namespace ImageProcessor.Imaging.Colors
/// <summary>
/// Gets the luminosity component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float L
{
@ -106,6 +108,7 @@ namespace ImageProcessor.Imaging.Colors
/// <summary>
/// Gets the saturation component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float S
{
@ -117,6 +120,7 @@ namespace ImageProcessor.Imaging.Colors
/// <summary>
/// Gets the alpha component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float A
{
@ -197,17 +201,11 @@ namespace ImageProcessor.Imaging.Colors
/// </returns>
public static implicit operator HslaColor(Color color)
{
HslaColor hslColor = new HslaColor(
color.GetHue() / 360.0f,
color.GetSaturation(),
color.GetBrightness(),
color.A / 255f);
return hslColor;
return FromColor(color);
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="System.Drawing.Color"/> to a
/// Allows the implicit conversion of an instance of <see cref="RgbaColor"/> to a
/// <see cref="HslaColor"/>.
/// </summary>
/// <param name="rgbaColor">
@ -218,14 +216,22 @@ namespace ImageProcessor.Imaging.Colors
/// </returns>
public static implicit operator HslaColor(RgbaColor rgbaColor)
{
Color color = rgbaColor;
HslaColor hslColor = new HslaColor(
color.GetHue() / 360.0f,
color.GetSaturation(),
color.GetBrightness(),
color.A / 255f);
return hslColor;
return FromColor(rgbaColor);
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="YCbCrColor"/> to a
/// <see cref="HslaColor"/>.
/// </summary>
/// <param name="ycbcrColor">
/// The instance of <see cref="YCbCrColor"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="YCbCrColor"/>.
/// </returns>
public static implicit operator HslaColor(YCbCrColor ycbcrColor)
{
return FromColor(ycbcrColor);
}
/// <summary>
@ -277,29 +283,22 @@ namespace ImageProcessor.Imaging.Colors
/// </returns>
public static implicit operator RgbaColor(HslaColor hslaColor)
{
float r = 0, g = 0, b = 0;
if (Math.Abs(hslaColor.l - 0) > .0001)
{
if (Math.Abs(hslaColor.s - 0) <= .0001)
{
r = g = b = hslaColor.l;
}
else
{
float temp2 = GetTemp2(hslaColor);
float temp1 = (2.0f * hslaColor.l) - temp2;
r = GetColorComponent(temp1, temp2, hslaColor.h + (1.0f / 3.0f));
g = GetColorComponent(temp1, temp2, hslaColor.h);
b = GetColorComponent(temp1, temp2, hslaColor.h - (1.0f / 3.0f));
}
}
return RgbaColor.FromColor(hslaColor);
}
return RgbaColor.FromRgba(
Convert.ToByte(255 * r),
Convert.ToByte(255 * g),
Convert.ToByte(255 * b),
Convert.ToByte(255 * hslaColor.a));
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="HslaColor"/> to a
/// <see cref="YCbCrColor"/>.
/// </summary>
/// <param name="hslaColor">
/// The instance of <see cref="HslaColor"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="YCbCrColor"/>.
/// </returns>
public static implicit operator YCbCrColor(HslaColor hslaColor)
{
return YCbCrColor.FromColor(hslaColor);
}
/// <summary>

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

@ -191,22 +191,37 @@ namespace ImageProcessor.Imaging.Colors
/// </returns>
public static implicit operator RgbaColor(Color color)
{
return new RgbaColor(color);
return FromColor(color);
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="System.Drawing.Color"/> to a
/// Allows the implicit conversion of an instance of <see cref="HslaColor"/> to a
/// <see cref="RgbaColor"/>.
/// </summary>
/// <param name="color">
/// The instance of <see cref="System.Drawing.Color"/> to convert.
/// <param name="hslaColor">
/// The instance of <see cref="HslaColor"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="RgbaColor"/>.
/// </returns>
public static implicit operator RgbaColor(HslaColor color)
public static implicit operator RgbaColor(HslaColor hslaColor)
{
return new RgbaColor(color);
return FromColor(hslaColor);
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="YCbCrColor"/> to a
/// <see cref="RgbaColor"/>.
/// </summary>
/// <param name="ycbcrColor">
/// The instance of <see cref="YCbCrColor"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="RgbaColor"/>.
/// </returns>
public static implicit operator RgbaColor(YCbCrColor ycbcrColor)
{
return FromColor(ycbcrColor);
}
/// <summary>
@ -239,6 +254,21 @@ namespace ImageProcessor.Imaging.Colors
return HslaColor.FromColor(rgba);
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="RgbaColor"/> to a
/// <see cref="YCbCrColor"/>.
/// </summary>
/// <param name="rgba">
/// The instance of <see cref="RgbaColor"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="YCbCrColor"/>.
/// </returns>
public static implicit operator YCbCrColor(RgbaColor rgba)
{
return YCbCrColor.FromColor(rgba);
}
/// <summary>
/// Returns a <see cref="System.String" /> that represents this instance.
/// </summary>

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

@ -4,7 +4,7 @@
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// Represents an YCbCr (luminance, chroma, chroma) color used in digital imaging systems.
// Represents an YCbCr (luminance, chroma, chroma) color conforming to the ITU-R BT.601 standard used in digital imaging systems.
// <see href="http://en.wikipedia.org/wiki/YCbCr" />
// </summary>
// --------------------------------------------------------------------------------------------------------------------
@ -14,10 +14,8 @@ 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.
/// Represents an YCbCr (luminance, chroma, chroma) color conforming to the ITU-R BT.601 standard used in digital imaging systems.
/// <see href="http://en.wikipedia.org/wiki/YCbCr"/>
/// </summary>
public struct YCbCrColor
@ -50,13 +48,14 @@ namespace ImageProcessor.Imaging.Colors
/// <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));
this.y = Math.Max(0f, Math.Min(255f, y));
this.cb = Math.Max(-255f, Math.Min(255f, cb));
this.cr = Math.Max(-255f, Math.Min(255f, cr));
}
/// <summary>
/// Gets the Y luminance component.
/// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary>
public float Y
{
@ -68,23 +67,25 @@ namespace ImageProcessor.Imaging.Colors
/// <summary>
/// Gets the U chroma component.
/// <remarks>A value ranging between -255 and 255.</remarks>
/// </summary>
public float Cb
{
get
{
return this.y;
return this.cb;
}
}
/// <summary>
/// Gets the V chroma component.
/// <remarks>A value ranging between -255 and 255.</remarks>
/// </summary>
public float Cr
{
get
{
return this.y;
return this.cr;
}
}
@ -114,12 +115,12 @@ namespace ImageProcessor.Imaging.Colors
/// </returns>
public static YCbCrColor FromColor(Color color)
{
float r = color.R;
float g = color.G;
float b = color.B;
byte r = color.R;
byte g = color.G;
byte 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 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);
@ -140,24 +141,148 @@ namespace ImageProcessor.Imaging.Colors
return FromColor(color);
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="RgbaColor"/> to a
/// <see cref="YCbCrColor"/>.
/// </summary>
/// <param name="rgbaColor">
/// The instance of <see cref="RgbaColor"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="YCbCrColor"/>.
/// </returns>
public static implicit operator YCbCrColor(RgbaColor rgbaColor)
{
return FromColor(rgbaColor);
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="HslaColor"/> to a
/// <see cref="YCbCrColor"/>.
/// </summary>
/// <param name="hslaColor">
/// The instance of <see cref="HslaColor"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="YCbCrColor"/>.
/// </returns>
public static implicit operator YCbCrColor(HslaColor hslaColor)
{
return FromColor(hslaColor);
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="YCbCrColor"/> to a
/// <see cref="System.Drawing.Color"/>.
/// </summary>
/// <param name="ycbcr">
/// <param name="ycbcrColor">
/// 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)
public static implicit operator Color(YCbCrColor ycbcrColor)
{
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();
float y = ycbcrColor.Y;
float cb = ycbcrColor.Cb - 128;
float cr = ycbcrColor.Cr - 128;
byte r = Convert.ToByte(Math.Max(0.0f, Math.Min(255f, y + (1.402 * cr))));
byte g = Convert.ToByte(Math.Max(0.0f, Math.Min(255f, y - (0.34414 * cb) - (0.71414 * cr))));
byte b = Convert.ToByte(Math.Max(0.0f, Math.Min(255f, y + (1.772 * cb))));
return Color.FromArgb(255, r, g, b);
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="YCbCrColor"/> to a
/// <see cref="RgbaColor"/>.
/// </summary>
/// <param name="ycbcrColor">
/// The instance of <see cref="YCbCrColor"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="RgbaColor"/>.
/// </returns>
public static implicit operator RgbaColor(YCbCrColor ycbcrColor)
{
return RgbaColor.FromColor(ycbcrColor);
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="YCbCrColor"/> to a
/// <see cref="HslaColor"/>.
/// </summary>
/// <param name="ycbcrColor">
/// The instance of <see cref="YCbCrColor"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="HslaColor"/>.
/// </returns>
public static implicit operator HslaColor(YCbCrColor ycbcrColor)
{
return HslaColor.FromColor(ycbcrColor);
}
/// <summary>
/// Returns a <see cref="System.String" /> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String" /> that represents this instance.
/// </returns>
public override string ToString()
{
if (this.IsEmpty())
{
return "YCbCrColor [Empty]";
}
return string.Format("YCbCrColor [ Y={0:#0.##}, Cb={1:#0.##}, Cr={2:#0.##}]", this.Y, this.Cb, this.Cr);
}
/// <summary>
/// Indicates whether this instance and a specified object are equal.
/// </summary>
/// <returns>
/// true if <paramref name="obj"/> and this instance are the same type and represent the same value; otherwise, false.
/// </returns>
/// <param name="obj">Another object to compare to. </param>
public override bool Equals(object obj)
{
if (obj is YCbCrColor)
{
Color thisColor = this;
Color otherColor = (YCbCrColor)obj;
return thisColor.Equals(otherColor);
}
return false;
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
public override int GetHashCode()
{
Color thisColor = this;
return thisColor.GetHashCode();
}
/// <summary>
/// Returns a value indicating whether the current instance is empty.
/// </summary>
/// <returns>
/// The true if this instance is empty; otherwise, false.
/// </returns>
private bool IsEmpty()
{
const float Epsilon = .0001f;
return Math.Abs(this.y - 0) <= Epsilon && Math.Abs(this.cb - 0) <= Epsilon &&
Math.Abs(this.cr - 0) <= Epsilon;
}
}
}

Loading…
Cancel
Save