diff --git a/src/ImageProcessor/Colors/Color.cs b/src/ImageProcessor/Colors/Color.cs
index 1cd19a231..716bd07ae 100644
--- a/src/ImageProcessor/Colors/Color.cs
+++ b/src/ImageProcessor/Colors/Color.cs
@@ -163,9 +163,7 @@ namespace ImageProcessor
/// Allows the implicit conversion of an instance of to a
/// .
///
- ///
- /// The instance of to convert.
- ///
+ /// The instance of to convert.
///
/// An instance of .
///
@@ -178,9 +176,7 @@ namespace ImageProcessor
/// Allows the implicit conversion of an instance of to a
/// .
///
- ///
- /// The instance of to convert.
- ///
+ /// The instance of to convert.
///
/// An instance of .
///
@@ -192,13 +188,32 @@ namespace ImageProcessor
return new Color(r, g, b);
}
+ ///
+ /// Allows the implicit conversion of an instance of to a
+ /// .
+ ///
+ /// The instance of to convert.
+ ///
+ /// An instance of .
+ ///
+ public static implicit operator Color(YCbCr color)
+ {
+ float y = color.Y;
+ float cb = color.Cb - 128;
+ float cr = color.Cr - 128;
+
+ float r = (float)(y + (1.402 * cr)) / 255f;
+ float g = (float)(y - (0.34414 * cb) - (0.71414 * cr)) / 255f;
+ float b = (float)(y + (1.772 * cb)) / 255f;
+
+ return new Color(r, g, b);
+ }
+
///
/// Allows the implicit conversion of an instance of to a
/// .
///
- ///
- /// The instance of to convert.
- ///
+ /// The instance of to convert.
///
/// An instance of .
///
diff --git a/src/ImageProcessor/Colors/Formats/Bgra32.cs b/src/ImageProcessor/Colors/Formats/Bgra32.cs
index 465e7d377..e86068d62 100644
--- a/src/ImageProcessor/Colors/Formats/Bgra32.cs
+++ b/src/ImageProcessor/Colors/Formats/Bgra32.cs
@@ -189,29 +189,6 @@ namespace ImageProcessor
return new Bgra32((255f * color.B).ToByte(), (255f * color.G).ToByte(), (255f * color.R).ToByte(), (255f * color.A).ToByte());
}
- ///
- /// Allows the implicit conversion of an instance of to a
- /// .
- ///
- ///
- /// The instance of to convert.
- ///
- ///
- /// An instance of .
- ///
- public static implicit operator Bgra32(YCbCr color)
- {
- float y = color.Y;
- float cb = color.Cb - 128;
- float cr = color.Cr - 128;
-
- byte b = (y + (1.772 * cb)).ToByte();
- byte g = (y - (0.34414 * cb) - (0.71414 * cr)).ToByte();
- byte r = (y + (1.402 * cr)).ToByte();
-
- return new Bgra32(b, g, r, 255);
- }
-
///
/// Compares two objects. The result specifies whether the values
/// of the , , , and
diff --git a/src/ImageProcessor/Colors/Formats/Cmyk.cs b/src/ImageProcessor/Colors/Formats/Cmyk.cs
index 3425c6ada..e20fe308c 100644
--- a/src/ImageProcessor/Colors/Formats/Cmyk.cs
+++ b/src/ImageProcessor/Colors/Formats/Cmyk.cs
@@ -141,13 +141,7 @@ namespace ImageProcessor
return !left.Equals(right);
}
- ///
- /// Indicates whether this instance and a specified object are equal.
- ///
- ///
- /// true if and this instance are the same type and represent the same value; otherwise, false.
- ///
- /// Another object to compare to.
+ ///
public override bool Equals(object obj)
{
if (obj is Cmyk)
@@ -194,7 +188,7 @@ namespace ImageProcessor
///
private static float Clamp(float value)
{
- return value.Clamp(0, 100);
+ return value.Clamp(0, 1);
}
///
diff --git a/src/ImageProcessor/Colors/Formats/Hsv.cs b/src/ImageProcessor/Colors/Formats/Hsv.cs
index 018c9bd18..a954fcf54 100644
--- a/src/ImageProcessor/Colors/Formats/Hsv.cs
+++ b/src/ImageProcessor/Colors/Formats/Hsv.cs
@@ -155,13 +155,7 @@ namespace ImageProcessor
return !left.Equals(right);
}
- ///
- /// Indicates whether this instance and a specified object are equal.
- ///
- ///
- /// true if and this instance are the same type and represent the same value; otherwise, false.
- ///
- /// Another object to compare to.
+ ///
public override bool Equals(object obj)
{
if (obj is Hsv)
diff --git a/src/ImageProcessor/Colors/Formats/YCbCr.cs b/src/ImageProcessor/Colors/Formats/YCbCr.cs
index a0c9a339b..c23d0ae0b 100644
--- a/src/ImageProcessor/Colors/Formats/YCbCr.cs
+++ b/src/ImageProcessor/Colors/Formats/YCbCr.cs
@@ -7,10 +7,11 @@ namespace ImageProcessor
{
using System;
using System.ComponentModel;
+ using System.Numerics;
///
/// Represents an YCbCr (luminance, chroma, chroma) color conforming to the
- /// ITU-R BT.601 standard used in digital imaging systems.
+ /// Full range standard used in digital imaging systems.
///
///
public struct YCbCr : IEquatable
@@ -21,64 +22,64 @@ namespace ImageProcessor
public static readonly YCbCr Empty = default(YCbCr);
///
- /// Gets the Y luminance component.
- /// A value ranging between 0 and 255.
+ /// The backing vector for SIMD support.
///
- public readonly float Y;
+ private Vector3 backingVector;
///
- /// Gets the Cb chroma component.
- /// A value ranging between 0 and 255.
+ /// Initializes a new instance of the struct.
///
- public readonly float Cb;
+ /// The y luminance component.
+ /// The cb chroma component.
+ /// The cr chroma component.
+ public YCbCr(float y, float cb, float cr)
+ : this()
+ {
+ this.backingVector.X = y.Clamp(0, 255);
+ this.backingVector.Y = cb.Clamp(0, 255);
+ this.backingVector.Z = cr.Clamp(0, 255);
+ }
///
- /// Gets the Cr chroma component.
+ /// Gets the Y luminance component.
/// A value ranging between 0 and 255.
///
- public readonly float Cr;
+ public float Y => this.backingVector.X;
///
- /// The epsilon for comparing floating point numbers.
+ /// Gets the Cb chroma component.
+ /// A value ranging between 0 and 255.
///
- private const float Epsilon = 0.0001f;
+ public float Cb => this.backingVector.Y;
///
- /// Initializes a new instance of the struct.
+ /// Gets the Cr chroma component.
+ /// A value ranging between 0 and 255.
///
- /// The y luminance component.
- /// The cb chroma component.
- /// The cr chroma component.
- public YCbCr(float y, float cb, float cr)
- {
- this.Y = y.ToByte();
- this.Cb = cb.ToByte();
- this.Cr = cr.ToByte();
- }
+ public float Cr => this.backingVector.Z;
///
/// Gets a value indicating whether this is empty.
///
[EditorBrowsable(EditorBrowsableState.Never)]
- public bool IsEmpty => Math.Abs(this.Y) < Epsilon
- && Math.Abs(this.Cb) < Epsilon
- && Math.Abs(this.Cr) < Epsilon;
+ public bool IsEmpty => this.backingVector.Equals(default(Vector3));
///
- /// Allows the implicit conversion of an instance of to a
+ /// Allows the implicit conversion of an instance of to a
/// .
///
///
- /// The instance of to convert.
+ /// The instance of to convert.
///
///
/// An instance of .
///
- public static implicit operator YCbCr(Bgra32 color)
+ public static implicit operator YCbCr(Color color)
{
- byte b = color.B;
- byte g = color.G;
- byte r = color.R;
+ color = color.Limited;
+ float r = color.R * 255f;
+ float g = color.G * 255f;
+ float b = color.B * 255f;
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));
@@ -88,9 +89,7 @@ namespace ImageProcessor
}
///
- /// Compares two objects. The result specifies whether the values
- /// of the , , and
- /// properties of the two objects are equal.
+ /// Compares two objects for equality.
///
///
/// The on the left side of the operand.
@@ -107,9 +106,7 @@ namespace ImageProcessor
}
///
- /// Compares two objects. The result specifies whether the values
- /// of the , , and
- /// properties of the two objects are unequal.
+ /// Compares two objects for inequality.
///
///
/// The on the left side of the operand.
@@ -125,50 +122,26 @@ namespace ImageProcessor
return !left.Equals(right);
}
- ///
- /// Indicates whether this instance and a specified object are equal.
- ///
- ///
- /// true if and this instance are the same type and represent the same value; otherwise, false.
- ///
- /// Another object to compare to.
+ ///
public override bool Equals(object obj)
{
if (obj is YCbCr)
{
YCbCr color = (YCbCr)obj;
- return Math.Abs(this.Y - color.Y) < Epsilon
- && Math.Abs(this.Cb - color.Cb) < Epsilon
- && Math.Abs(this.Cr - color.Cr) < Epsilon;
+ return this.backingVector == color.backingVector;
}
return false;
}
- ///
- /// Returns the hash code for this instance.
- ///
- ///
- /// A 32-bit signed integer that is the hash code for this instance.
- ///
+ ///
public override int GetHashCode()
{
- unchecked
- {
- int hashCode = this.Y.GetHashCode();
- hashCode = (hashCode * 397) ^ this.Cb.GetHashCode();
- hashCode = (hashCode * 397) ^ this.Cr.GetHashCode();
- return hashCode;
- }
+ return GetHashCode(this);
}
- ///
- /// Returns the fully qualified type name of this instance.
- ///
- ///
- /// A containing a fully qualified type name.
- ///
+ ///
public override string ToString()
{
if (this.IsEmpty)
@@ -179,18 +152,21 @@ namespace ImageProcessor
return $"YCbCr [ Y={this.Y:#0.##}, Cb={this.Cb:#0.##}, Cr={this.Cr:#0.##} ]";
}
+ ///
+ public bool Equals(YCbCr other)
+ {
+ return this.backingVector.Equals(other.backingVector);
+ }
+
///
- /// Indicates whether the current object is equal to another object of the same type.
+ /// Returns the hash code for this instance.
///
+ ///
+ /// The instance of to return the hash code for.
+ ///
///
- /// True if the current object is equal to the parameter; otherwise, false.
+ /// A 32-bit signed integer that is the hash code for this instance.
///
- /// An object to compare with this object.
- public bool Equals(YCbCr other)
- {
- return Math.Abs(this.Y - other.Y) < Epsilon
- && Math.Abs(this.Cb - other.Cb) < Epsilon
- && Math.Abs(this.Cr - other.Cr) < Epsilon;
- }
+ private static int GetHashCode(YCbCr color) => color.backingVector.GetHashCode();
}
}
diff --git a/tests/ImageProcessor.Tests/Colors/ColorConversionTests.cs b/tests/ImageProcessor.Tests/Colors/ColorConversionTests.cs
index ecf7f1267..11d2529e8 100644
--- a/tests/ImageProcessor.Tests/Colors/ColorConversionTests.cs
+++ b/tests/ImageProcessor.Tests/Colors/ColorConversionTests.cs
@@ -25,15 +25,15 @@ namespace ImageProcessor.Tests
public class ColorConversionTests
{
///
- /// Tests the implicit conversion from to .
+ /// Tests the implicit conversion from to .
///
[Fact]
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation",
Justification = "Reviewed. Suppression is OK here.")]
- public void BgrToYCbCr()
+ public void ColorToYCbCr()
{
// White
- Bgra32 color = new Bgra32(255, 255, 255, 255);
+ Color color = new Color(1, 1, 1);
YCbCr yCbCr = color;
Assert.Equal(255, yCbCr.Y);
@@ -41,14 +41,14 @@ namespace ImageProcessor.Tests
Assert.Equal(128, yCbCr.Cr);
// Black
- Bgra32 color2 = new Bgra32(0, 0, 0, 255);
+ Color color2 = new Color(0, 0, 0);
YCbCr yCbCr2 = color2;
Assert.Equal(0, yCbCr2.Y);
Assert.Equal(128, yCbCr2.Cb);
Assert.Equal(128, yCbCr2.Cr);
// Grey
- Bgra32 color3 = new Bgra32(128, 128, 128, 255);
+ Color color3 = new Color(.5f, .5f, .5f);
YCbCr yCbCr3 = color3;
Assert.Equal(128, yCbCr3.Y);
Assert.Equal(128, yCbCr3.Cb);
@@ -56,39 +56,39 @@ namespace ImageProcessor.Tests
}
///
- /// Tests the implicit conversion from to .
+ /// Tests the implicit conversion from to .
///
[Fact]
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation",
Justification = "Reviewed. Suppression is OK here.")]
- public void YCbCrToBgr()
+ public void YCbCrToColor()
{
// White
YCbCr yCbCr = new YCbCr(255, 128, 128);
- Bgra32 color = yCbCr;
+ Color color = yCbCr;
- Assert.Equal(255, color.B);
- Assert.Equal(255, color.G);
- Assert.Equal(255, color.R);
- Assert.Equal(255, color.A);
+ Assert.Equal(1f, color.R, 1);
+ Assert.Equal(1f, color.G, 1);
+ Assert.Equal(1f, color.B, 1);
+ Assert.Equal(1f, color.A, 1);
// Black
YCbCr yCbCr2 = new YCbCr(0, 128, 128);
- Bgra32 color2 = yCbCr2;
+ Color color2 = yCbCr2;
- Assert.Equal(0, color2.B);
- Assert.Equal(0, color2.G);
Assert.Equal(0, color2.R);
- Assert.Equal(255, color2.A);
+ Assert.Equal(0, color2.G);
+ Assert.Equal(0, color2.B);
+ Assert.Equal(1, color2.A);
// Grey
YCbCr yCbCr3 = new YCbCr(128, 128, 128);
- Bgra32 color3 = yCbCr3;
+ Color color3 = yCbCr3;
- Assert.Equal(128, color3.B);
- Assert.Equal(128, color3.G);
- Assert.Equal(128, color3.R);
- Assert.Equal(255, color3.A);
+ Assert.Equal(.5f, color3.R, 1);
+ Assert.Equal(.5f, color3.G, 1);
+ Assert.Equal(.5f, color3.B, 1);
+ Assert.Equal(1f, color3.A, 1);
}
///