diff --git a/src/ImageProcessor/Colors/Color.cs b/src/ImageProcessor/Colors/Color.cs
index b8b554804..1cd19a231 100644
--- a/src/ImageProcessor/Colors/Color.cs
+++ b/src/ImageProcessor/Colors/Color.cs
@@ -174,6 +174,24 @@ namespace ImageProcessor
return new Color(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f);
}
+ ///
+ /// Allows the implicit conversion of an instance of to a
+ /// .
+ ///
+ ///
+ /// The instance of to convert.
+ ///
+ ///
+ /// An instance of .
+ ///
+ public static implicit operator Color(Cmyk cmykColor)
+ {
+ float r = (1 - cmykColor.C) * (1 - cmykColor.K);
+ float g = (1 - cmykColor.M) * (1 - cmykColor.K);
+ float b = (1 - cmykColor.Y) * (1 - cmykColor.K);
+ return new Color(r, g, b);
+ }
+
///
/// Allows the implicit conversion of an instance of to a
/// .
diff --git a/src/ImageProcessor/Colors/Formats/Bgra32.cs b/src/ImageProcessor/Colors/Formats/Bgra32.cs
index f9b10069e..465e7d377 100644
--- a/src/ImageProcessor/Colors/Formats/Bgra32.cs
+++ b/src/ImageProcessor/Colors/Formats/Bgra32.cs
@@ -212,24 +212,6 @@ namespace ImageProcessor
return new Bgra32(b, g, r, 255);
}
- ///
- /// Allows the implicit conversion of an instance of to a
- /// .
- ///
- ///
- /// The instance of to convert.
- ///
- ///
- /// An instance of .
- ///
- public static implicit operator Bgra32(Cmyk cmykColor)
- {
- int red = Convert.ToInt32((1 - (cmykColor.C / 100)) * (1 - (cmykColor.K / 100)) * 255.0);
- int green = Convert.ToInt32((1 - (cmykColor.M / 100)) * (1 - (cmykColor.K / 100)) * 255.0);
- int blue = Convert.ToInt32((1 - (cmykColor.Y / 100)) * (1 - (cmykColor.K / 100)) * 255.0);
- return new Bgra32(blue.ToByte(), green.ToByte(), red.ToByte());
- }
-
///
/// 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 377d35ecc..3425c6ada 100644
--- a/src/ImageProcessor/Colors/Formats/Cmyk.cs
+++ b/src/ImageProcessor/Colors/Formats/Cmyk.cs
@@ -7,6 +7,7 @@ namespace ImageProcessor
{
using System;
using System.ComponentModel;
+ using System.Numerics;
///
/// Represents an CMYK (cyan, magenta, yellow, keyline) color.
@@ -19,60 +20,63 @@ namespace ImageProcessor
public static readonly Cmyk Empty = default(Cmyk);
///
- /// Gets the cyan color component.
+ /// The epsilon for comparing floating point numbers.
///
- /// A value ranging between 0 and 100.
- public readonly float C;
+ private const float Epsilon = 0.0001f;
///
- /// Gets the magenta color component.
+ /// The backing vector for SIMD support.
///
- /// A value ranging between 0 and 100.
- public readonly float M;
+ private Vector4 backingVector;
///
- /// Gets the yellow color component.
+ /// Initializes a new instance of the struct.
///
- /// A value ranging between 0 and 100.
- public readonly float Y;
+ /// The cyan component.
+ /// The magenta component.
+ /// The yellow component.
+ /// The keyline black component.
+ public Cmyk(float cyan, float magenta, float yellow, float keyline)
+ : this()
+ {
+ this.backingVector.X = Clamp(cyan);
+ this.backingVector.Y = Clamp(magenta);
+ this.backingVector.Z = Clamp(yellow);
+ this.backingVector.W = Clamp(keyline);
+ }
///
- /// Gets the keyline black color component.
+ /// Gets the cyan color component.
+ /// A value ranging between 0 and 1.
///
- /// A value ranging between 0 and 100.
- public readonly float K;
+ public float C => this.backingVector.X;
///
- /// The epsilon for comparing floating point numbers.
+ /// Gets the magenta color component.
+ /// A value ranging between 0 and 1.
///
- private const float Epsilon = 0.0001f;
+ public float M => this.backingVector.Y;
///
- /// Initializes a new instance of the struct.
+ /// Gets the yellow color component.
+ /// A value ranging between 0 and 1.
///
- /// The cyan component.
- /// The magenta component.
- /// The yellow component.
- /// The keyline black component.
- public Cmyk(float cyan, float magenta, float yellow, float keyline)
- {
- this.C = Clamp(cyan);
- this.M = Clamp(magenta);
- this.Y = Clamp(yellow);
- this.K = Clamp(keyline);
- }
+ public float Y => this.backingVector.Z;
+
+ ///
+ /// Gets the keyline black color component.
+ /// A value ranging between 0 and 1.
+ ///
+ public float K => this.backingVector.W;
///
/// Gets a value indicating whether this is empty.
///
[EditorBrowsable(EditorBrowsableState.Never)]
- public bool IsEmpty => Math.Abs(this.C) < Epsilon
- && Math.Abs(this.M) < Epsilon
- && Math.Abs(this.Y) < Epsilon
- && Math.Abs(this.K) < Epsilon;
+ public bool IsEmpty => this.backingVector.Equals(default(Vector4));
///
- /// Allows the implicit conversion of an instance of to a
+ /// Allows the implicit conversion of an instance of to a
/// .
///
///
@@ -81,30 +85,30 @@ namespace ImageProcessor
///
/// An instance of .
///
- public static implicit operator Cmyk(Bgra32 color)
+ public static implicit operator Cmyk(Color color)
{
- float c = (255f - color.R) / 255;
- float m = (255f - color.G) / 255;
- float y = (255f - color.B) / 255;
+ color = color.Limited;
+
+ float c = 1f - color.R;
+ float m = 1f - color.G;
+ float y = 1f - color.B;
float k = Math.Min(c, Math.Min(m, y));
- if (Math.Abs(k - 1.0) <= Epsilon)
+ if (Math.Abs(k - 1.0f) <= Epsilon)
{
- return new Cmyk(0, 0, 0, 100);
+ return new Cmyk(0, 0, 0, 1);
}
- c = ((c - k) / (1 - k)) * 100;
- m = ((m - k) / (1 - k)) * 100;
- y = ((y - k) / (1 - k)) * 100;
+ c = (c - k) / (1 - k);
+ m = (m - k) / (1 - k);
+ y = (y - k) / (1 - k);
- return new Cmyk(c, m, y, k * 100);
+ return new Cmyk(c, m, y, k);
}
///
- /// 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.
@@ -121,9 +125,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.
@@ -152,39 +154,19 @@ namespace ImageProcessor
{
Cmyk color = (Cmyk)obj;
- return Math.Abs(this.C - color.C) < Epsilon
- && Math.Abs(this.M - color.M) < Epsilon
- && Math.Abs(this.Y - color.Y) < Epsilon
- && Math.Abs(this.K - color.K) < 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.C.GetHashCode();
- hashCode = (hashCode * 397) ^ this.M.GetHashCode();
- hashCode = (hashCode * 397) ^ this.Y.GetHashCode();
- hashCode = (hashCode * 397) ^ this.K.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)
@@ -195,19 +177,10 @@ namespace ImageProcessor
return $"Cmyk [ C={this.C:#0.##}, M={this.M:#0.##}, Y={this.Y:#0.##}, K={this.K:#0.##}]";
}
- ///
- /// Indicates whether the current object is equal to another object of the same type.
- ///
- ///
- /// True if the current object is equal to the parameter; otherwise, false.
- ///
- /// An object to compare with this object.
+ ///
public bool Equals(Cmyk other)
{
- return Math.Abs(this.C - other.C) < Epsilon
- && Math.Abs(this.M - other.M) < Epsilon
- && Math.Abs(this.Y - other.Y) < Epsilon
- && Math.Abs(this.K - other.Y) < Epsilon;
+ return this.backingVector.Equals(other.backingVector);
}
///
@@ -223,5 +196,16 @@ namespace ImageProcessor
{
return value.Clamp(0, 100);
}
+
+ ///
+ /// Returns the hash code for this instance.
+ ///
+ ///
+ /// The instance of to return the hash code for.
+ ///
+ ///
+ /// A 32-bit signed integer that is the hash code for this instance.
+ ///
+ private static int GetHashCode(Cmyk color) => color.backingVector.GetHashCode();
}
}
diff --git a/src/ImageProcessor/Colors/Formats/Hsv.cs b/src/ImageProcessor/Colors/Formats/Hsv.cs
index 32aedc96e..018c9bd18 100644
--- a/src/ImageProcessor/Colors/Formats/Hsv.cs
+++ b/src/ImageProcessor/Colors/Formats/Hsv.cs
@@ -122,7 +122,7 @@ namespace ImageProcessor
}
///
- /// Compares two objects for equality
+ /// Compares two objects for equality.
///
///
/// The on the left side of the operand.
diff --git a/tests/ImageProcessor.Tests/Colors/ColorConversionTests.cs b/tests/ImageProcessor.Tests/Colors/ColorConversionTests.cs
index f8087d4d4..ecf7f1267 100644
--- a/tests/ImageProcessor.Tests/Colors/ColorConversionTests.cs
+++ b/tests/ImageProcessor.Tests/Colors/ColorConversionTests.cs
@@ -17,7 +17,11 @@ namespace ImageProcessor.Tests
///
/// Test conversion between the various color structs.
- ///
+ ///
+ ///
+ /// Output values have been compared with
+ /// and for accuracy.
+ ///
public class ColorConversionTests
{
///
@@ -163,90 +167,90 @@ namespace ImageProcessor.Tests
for (int i = 0; i < 1000; i++)
{
Color color4 = new Color(random.Next(1), random.Next(1), random.Next(1));
- Hsv hsb4 = color4;
- Assert.Equal(color4, (Color)hsb4);
+ Hsv hsv4 = color4;
+ Assert.Equal(color4, (Color)hsv4);
}
}
///
- /// 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 BgrToCmyk()
+ public void ColorToCmyk()
{
// White
- Bgra32 color = new Bgra32(255, 255, 255, 255);
+ Color color = new Color(1, 1, 1);
Cmyk cmyk = color;
- Assert.Equal(0, cmyk.C);
- Assert.Equal(0, cmyk.M);
- Assert.Equal(0, cmyk.Y);
- Assert.Equal(0, cmyk.K);
+ Assert.Equal(0, cmyk.C, 1);
+ Assert.Equal(0, cmyk.M, 1);
+ Assert.Equal(0, cmyk.Y, 1);
+ Assert.Equal(0, cmyk.K, 1);
// Black
- Bgra32 color2 = new Bgra32(0, 0, 0, 255);
+ Color color2 = new Color(0, 0, 0);
Cmyk cmyk2 = color2;
- Assert.Equal(0, cmyk2.C);
- Assert.Equal(0, cmyk2.M);
- Assert.Equal(0, cmyk2.Y);
- Assert.Equal(100, cmyk2.K);
+ Assert.Equal(0, cmyk2.C, 1);
+ Assert.Equal(0, cmyk2.M, 1);
+ Assert.Equal(0, cmyk2.Y, 1);
+ Assert.Equal(1, cmyk2.K, 1);
// Grey
- Bgra32 color3 = new Bgra32(128, 128, 128, 255);
+ Color color3 = new Color(128 / 255f, 128 / 255f, 128 / 255f);
Cmyk cmyk3 = color3;
- Assert.Equal(0, cmyk3.C);
- Assert.Equal(0, cmyk3.M);
- Assert.Equal(0, cmyk3.Y);
- Assert.Equal(49.8, cmyk3.K, 1); // Checked with other tools.
+ Assert.Equal(0f, cmyk3.C, 1);
+ Assert.Equal(0f, cmyk3.M, 1);
+ Assert.Equal(0f, cmyk3.Y, 1);
+ Assert.Equal(0.498, cmyk3.K, 2); // Checked with other online converters.
// Cyan
- Bgra32 color4 = new Bgra32(255, 255, 0, 255);
+ Color color4 = new Color(0, 1, 1);
Cmyk cmyk4 = color4;
- Assert.Equal(100, cmyk4.C);
- Assert.Equal(0, cmyk4.M);
- Assert.Equal(0, cmyk4.Y);
- Assert.Equal(0, cmyk4.K);
+ Assert.Equal(1, cmyk4.C, 1);
+ Assert.Equal(0f, cmyk4.M, 1);
+ Assert.Equal(0f, cmyk4.Y, 1);
+ Assert.Equal(0f, cmyk4.K, 1);
}
///
- /// Tests the implicit conversion from to .
+ /// Tests the implicit conversion from to .
///
[Fact]
- public void CmykToBgr()
+ public void CmykToColor()
{
// Dark moderate pink.
- Cmyk cmyk = new Cmyk(49.8f, 74.9f, 58.4f, 0);
- Bgra32 bgra32 = cmyk;
+ Cmyk cmyk = new Cmyk(0f, .5f, .171f, .498f);
+ Color color = cmyk;
- Assert.Equal(bgra32.B, 106);
- Assert.Equal(bgra32.G, 64);
- Assert.Equal(bgra32.R, 128);
+ Assert.Equal(color.R, 128 / 255f, 1);
+ Assert.Equal(color.G, 64 / 255f, 1);
+ Assert.Equal(color.B, 106 / 255f, 1);
// Ochre
- Cmyk cmyk2 = new Cmyk(20, 53.3f, 86.7f, 0);
- Bgra32 bgra2 = cmyk2;
+ Cmyk cmyk2 = new Cmyk(0, .416f, .833f, .199f);
+ Color color2 = cmyk2;
- Assert.Equal(bgra2.B, 34);
- Assert.Equal(bgra2.G, 119);
- Assert.Equal(bgra2.R, 204);
+ Assert.Equal(color2.R, 204 / 255f, 1);
+ Assert.Equal(color2.G, 119 / 255f, 1);
+ Assert.Equal(color2.B, 34 / 255f, 1);
// White
Cmyk cmyk3 = new Cmyk(0, 0, 0, 0);
- Bgra32 bgra3 = cmyk3;
+ Color color3 = cmyk3;
- Assert.Equal(bgra3.B, 255);
- Assert.Equal(bgra3.G, 255);
- Assert.Equal(bgra3.R, 255);
+ Assert.Equal(color3.R, 1f, 1);
+ Assert.Equal(color3.G, 1f, 1);
+ Assert.Equal(color3.B, 1f, 1);
// Check others.
Random random = new Random(0);
for (int i = 0; i < 1000; i++)
{
- Bgra32 bgra4 = new Bgra32((byte)random.Next(255), (byte)random.Next(255), (byte)random.Next(255));
- Cmyk cmyk4 = bgra4;
- Assert.Equal(bgra4, (Bgra32)cmyk4);
+ Color color4 = new Color(random.Next(1), random.Next(1), random.Next(1));
+ Cmyk cmyk4 = color4;
+ Assert.Equal(color4, (Color)cmyk4);
}
}
}