diff --git a/src/ImageSharp/Colors/Spaces/CieXyChromaticityCoordinates.cs b/src/ImageSharp/Colors/Spaces/CieXyChromaticityCoordinates.cs
new file mode 100644
index 000000000..20c7997bb
--- /dev/null
+++ b/src/ImageSharp/Colors/Spaces/CieXyChromaticityCoordinates.cs
@@ -0,0 +1,145 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Colors.Spaces
+{
+ using System;
+ using System.ComponentModel;
+ using System.Numerics;
+
+ ///
+ /// Represents the coordinates of CIEXY chromaticity space
+ ///
+ public struct CieXyChromaticityCoordinates : IEquatable, IAlmostEquatable
+ {
+ ///
+ /// Represents a that has X, Y values set to zero.
+ ///
+ public static readonly CieXyChromaticityCoordinates Empty = default(CieXyChromaticityCoordinates);
+
+ ///
+ /// The backing vector for SIMD support.
+ ///
+ private readonly Vector2 backingVector;
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// Chromaticity coordinate x (usually from 0 to 1)
+ /// Chromaticity coordinate y (usually from 0 to 1)
+ public CieXyChromaticityCoordinates(float x, float y)
+ : this(new Vector2(x, y))
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The vector containing the XY Chromaticity coordinates
+ public CieXyChromaticityCoordinates(Vector2 vector)
+ {
+ this.backingVector = vector;
+ }
+
+ ///
+ /// Gets the chromaticity X-coordinate.
+ ///
+ ///
+ /// Ranges usually from 0 to 1.
+ ///
+ public float X => this.backingVector.X;
+
+ ///
+ /// Gets the chromaticity Y-coordinate
+ ///
+ ///
+ /// Ranges usually from 0 to 1.
+ ///
+ public float Y => this.backingVector.Y;
+
+ ///
+ /// Gets a value indicating whether this is empty.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool IsEmpty => this.Equals(Empty);
+
+ ///
+ /// Compares two objects for equality.
+ ///
+ ///
+ /// The on the left side of the operand.
+ ///
+ ///
+ /// The on the right side of the operand.
+ ///
+ ///
+ /// True if the current left is equal to the parameter; otherwise, false.
+ ///
+ public static bool operator ==(CieXyChromaticityCoordinates left, CieXyChromaticityCoordinates right)
+ {
+ return left.Equals(right);
+ }
+
+ ///
+ /// Compares two objects for inequality
+ ///
+ ///
+ /// The on the left side of the operand.
+ ///
+ ///
+ /// The on the right side of the operand.
+ ///
+ ///
+ /// True if the current left is unequal to the parameter; otherwise, false.
+ ///
+ public static bool operator !=(CieXyChromaticityCoordinates left, CieXyChromaticityCoordinates right)
+ {
+ return !left.Equals(right);
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ return this.backingVector.GetHashCode();
+ }
+
+ ///
+ public override string ToString()
+ {
+ if (this.IsEmpty)
+ {
+ return "CieXyChromaticityCoordinates [Empty]";
+ }
+
+ return $"CieXyChromaticityCoordinates [ X={this.X:#0.##}, Y={this.Y:#0.##}]";
+ }
+
+ ///
+ public override bool Equals(object obj)
+ {
+ if (obj is CieXyChromaticityCoordinates)
+ {
+ return this.Equals((CieXyChromaticityCoordinates)obj);
+ }
+
+ return false;
+ }
+
+ ///
+ public bool Equals(CieXyChromaticityCoordinates other)
+ {
+ return this.backingVector.Equals(other.backingVector);
+ }
+
+ ///
+ public bool AlmostEquals(CieXyChromaticityCoordinates other, float precision)
+ {
+ Vector2 result = Vector2.Abs(this.backingVector - other.backingVector);
+
+ return result.X <= precision
+ && result.Y <= precision;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/CieConstants.cs b/src/ImageSharp/Colors/Spaces/Conversion/CieConstants.cs
index 2134ea214..bff7c4e84 100644
--- a/src/ImageSharp/Colors/Spaces/Conversion/CieConstants.cs
+++ b/src/ImageSharp/Colors/Spaces/Conversion/CieConstants.cs
@@ -3,7 +3,7 @@
// Licensed under the Apache License, Version 2.0.
//
-namespace ImageSharp.Colors.Conversion
+namespace ImageSharp.Colors.Spaces.Conversion
{
///
/// Constants use for Cie conversion calculations
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Adapt.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Adapt.cs
index daea45efe..5f8432dfd 100644
--- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Adapt.cs
+++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Adapt.cs
@@ -3,10 +3,11 @@
// Licensed under the Apache License, Version 2.0.
//
-namespace ImageSharp.Colors.Conversion
+namespace ImageSharp.Colors.Spaces.Conversion
{
using System;
- using Spaces;
+
+ using ImageSharp.Colors.Spaces;
///
/// Converts between color spaces ensuring that the color is adapted using chromatic adaptation.
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieLab.cs
index e8cb6f643..17b57e4c7 100644
--- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieLab.cs
+++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieLab.cs
@@ -3,10 +3,10 @@
// Licensed under the Apache License, Version 2.0.
//
-namespace ImageSharp.Colors.Conversion
+namespace ImageSharp.Colors.Spaces.Conversion
{
- using Implementation;
- using Spaces;
+ using ImageSharp.Colors.Spaces;
+ using ImageSharp.Colors.Spaces.Conversion.Implementation.CieLab;
///
/// Converts between color spaces ensuring that the color is adapted using chromatic adaptation.
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieXyz.cs
index 77a90bd0e..46bcfbc1a 100644
--- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieXyz.cs
+++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieXyz.cs
@@ -3,10 +3,10 @@
// Licensed under the Apache License, Version 2.0.
//
-namespace ImageSharp.Colors.Conversion
+namespace ImageSharp.Colors.Spaces.Conversion
{
- using Implementation;
- using Spaces;
+ using ImageSharp.Colors.Spaces;
+ using ImageSharp.Colors.Spaces.Conversion.Implementation.CieLab;
///
/// Converts between color spaces ensuring that the color is adapted using chromatic adaptation.
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Lms.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Lms.cs
index 7af17ef2e..25f594177 100644
--- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Lms.cs
+++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Lms.cs
@@ -3,10 +3,9 @@
// Licensed under the Apache License, Version 2.0.
//
-namespace ImageSharp.Colors.Conversion
+namespace ImageSharp.Colors.Spaces.Conversion
{
- using Implementation;
- using Spaces;
+ using ImageSharp.Colors.Spaces;
///
/// Converts between color spaces ensuring that the color is adapted using chromatic adaptation.
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.cs
index 9cc3e0f93..bb6184371 100644
--- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.cs
+++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.cs
@@ -3,11 +3,12 @@
// Licensed under the Apache License, Version 2.0.
//
-namespace ImageSharp.Colors.Conversion
+namespace ImageSharp.Colors.Spaces.Conversion
{
using System.Numerics;
- using Implementation;
- using Spaces;
+
+ using ImageSharp.Colors.Spaces;
+ using ImageSharp.Colors.Spaces.Conversion.Implementation.Lms;
///
/// Converts between color spaces ensuring that the color is adapted using chromatic adaptation.
@@ -23,7 +24,7 @@ namespace ImageSharp.Colors.Conversion
private CieXyzAndLmsConverter cachedCieXyzAndLmsConverter;
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
public ColorSpaceConverter()
{
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/IChromaticAdaptation.cs b/src/ImageSharp/Colors/Spaces/Conversion/IChromaticAdaptation.cs
index d97d1bd1c..1c75fa655 100644
--- a/src/ImageSharp/Colors/Spaces/Conversion/IChromaticAdaptation.cs
+++ b/src/ImageSharp/Colors/Spaces/Conversion/IChromaticAdaptation.cs
@@ -3,9 +3,9 @@
// Licensed under the Apache License, Version 2.0.
//
-namespace ImageSharp.Colors.Conversion
+namespace ImageSharp.Colors.Spaces.Conversion
{
- using Spaces;
+ using ImageSharp.Colors.Spaces;
///
/// Chromatic adaptation.
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/IColorConversion.cs b/src/ImageSharp/Colors/Spaces/Conversion/IColorConversion.cs
index 73a90cdde..d9e7cb059 100644
--- a/src/ImageSharp/Colors/Spaces/Conversion/IColorConversion.cs
+++ b/src/ImageSharp/Colors/Spaces/Conversion/IColorConversion.cs
@@ -3,7 +3,7 @@
// Licensed under the Apache License, Version 2.0.
//
-namespace ImageSharp.Colors.Conversion
+namespace ImageSharp.Colors.Spaces.Conversion
{
///
/// Converts color between two color spaces.
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/Implementation/CieLab/CieLabToCieXyzConverter.cs b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/CieLab/CieLabToCieXyzConverter.cs
index 3f94ef607..d12c23844 100644
--- a/src/ImageSharp/Colors/Spaces/Conversion/Implementation/CieLab/CieLabToCieXyzConverter.cs
+++ b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/CieLab/CieLabToCieXyzConverter.cs
@@ -3,10 +3,11 @@
// Licensed under the Apache License, Version 2.0.
//
-namespace ImageSharp.Colors.Conversion.Implementation
+namespace ImageSharp.Colors.Spaces.Conversion.Implementation.CieLab
{
using System;
- using Spaces;
+
+ using ImageSharp.Colors.Spaces;
///
/// Converts from to .
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/Implementation/CieLab/CieXyzToCieLabConverter.cs b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/CieLab/CieXyzToCieLabConverter.cs
index 34540512d..29fe8be8d 100644
--- a/src/ImageSharp/Colors/Spaces/Conversion/Implementation/CieLab/CieXyzToCieLabConverter.cs
+++ b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/CieLab/CieXyzToCieLabConverter.cs
@@ -3,10 +3,11 @@
// Licensed under the Apache License, Version 2.0.
//
-namespace ImageSharp.Colors.Conversion.Implementation
+namespace ImageSharp.Colors.Spaces.Conversion.Implementation.CieLab
{
using System;
- using Spaces;
+
+ using ImageSharp.Colors.Spaces;
///
/// Converts from to .
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Lms/CieXyzAndLmsConverter.cs b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Lms/CieXyzAndLmsConverter.cs
index e467946c5..c169e6011 100644
--- a/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Lms/CieXyzAndLmsConverter.cs
+++ b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Lms/CieXyzAndLmsConverter.cs
@@ -3,10 +3,11 @@
// Licensed under the Apache License, Version 2.0.
//
-namespace ImageSharp.Colors.Conversion.Implementation
+namespace ImageSharp.Colors.Spaces.Conversion.Implementation.Lms
{
using System.Numerics;
- using Spaces;
+
+ using ImageSharp.Colors.Spaces;
///
/// Color converter between CIE XYZ and LMS
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Lms/LmsAdaptationMatrix.cs b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Lms/LmsAdaptationMatrix.cs
index 25344af68..1c06425e7 100644
--- a/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Lms/LmsAdaptationMatrix.cs
+++ b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Lms/LmsAdaptationMatrix.cs
@@ -4,7 +4,7 @@
//
// ReSharper disable InconsistentNaming
-namespace ImageSharp.Colors.Conversion.Implementation
+namespace ImageSharp.Colors.Spaces.Conversion.Implementation.Lms
{
using System.Numerics;
@@ -13,7 +13,7 @@ namespace ImageSharp.Colors.Conversion.Implementation
/// Used in
///
///
- /// AdaptionMatrix3X3 data obtained from:
+ /// Matrix data obtained from:
/// Two New von Kries Based Chromatic Adaptation Transforms Found by Numerical Optimization
/// S. Bianco, R. Schettini
/// DISCo, Department of Informatics, Systems and Communication, University of Milan-Bicocca, viale Sarca 336, 20126 Milan, Italy
@@ -98,4 +98,4 @@ namespace ImageSharp.Colors.Conversion.Implementation
M44 = 1F
};
}
-}
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/GammaCompanding.cs b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/GammaCompanding.cs
new file mode 100644
index 000000000..1e280d8fd
--- /dev/null
+++ b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/GammaCompanding.cs
@@ -0,0 +1,48 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Colors.Spaces.Conversion.Implementation.Rgb
+{
+ using System;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Implements gamma companding
+ ///
+ ///
+ ///
+ ///
+ ///
+ public class GammaCompanding : ICompanding
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The gamma value.
+ public GammaCompanding(float gamma)
+ {
+ this.Gamma = gamma;
+ }
+
+ ///
+ /// Gets the gamma value
+ ///
+ public float Gamma { get; }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public float Expand(float channel)
+ {
+ return (float)Math.Pow(channel, this.Gamma);
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public float Compress(float channel)
+ {
+ return (float)Math.Pow(channel, 1 / this.Gamma);
+ }
+ }
+}
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/LCompanding.cs b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/LCompanding.cs
new file mode 100644
index 000000000..aa28dd8a9
--- /dev/null
+++ b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/LCompanding.cs
@@ -0,0 +1,37 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Colors.Spaces.Conversion.Implementation.Rgb
+{
+ using System;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Implements L* companding
+ ///
+ ///
+ /// For more info see:
+ ///
+ ///
+ ///
+ public class LCompanding : ICompanding
+ {
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public float Expand(float channel)
+ {
+ return channel <= 0.08 ? 100 * channel / CieConstants.Kappa : (float)Math.Pow((channel + 0.16) / 1.16, 3);
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public float Compress(float channel)
+ {
+ return channel <= CieConstants.Epsilon
+ ? channel * CieConstants.Kappa / 100F
+ : (float)Math.Pow(1.16 * channel, 0.333333333333333D) - 0.16F;
+ }
+ }
+}
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/RGBPrimariesChromaticityCoordinates.cs b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/RGBPrimariesChromaticityCoordinates.cs
new file mode 100644
index 000000000..10546f17d
--- /dev/null
+++ b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/RGBPrimariesChromaticityCoordinates.cs
@@ -0,0 +1,107 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Colors.Spaces.Conversion.Implementation.Rgb
+{
+ using System;
+
+ ///
+ /// Represents the chromaticity coordinates of RGB primaries.
+ /// One of the specifiers of .
+ ///
+ public struct RgbPrimariesChromaticityCoordinates : IEquatable
+ {
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The chomaticity coordinates of the red channel.
+ /// The chomaticity coordinates of the green channel.
+ /// The chomaticity coordinates of the blue channel.
+ public RgbPrimariesChromaticityCoordinates(CieXyChromaticityCoordinates r, CieXyChromaticityCoordinates g, CieXyChromaticityCoordinates b)
+ {
+ this.R = r;
+ this.G = g;
+ this.B = b;
+ }
+
+ ///
+ /// Gets the chomaticity coordinates of the red channel.
+ ///
+ public CieXyChromaticityCoordinates R { get; }
+
+ ///
+ /// Gets the chomaticity coordinates of the green channel.
+ ///
+ public CieXyChromaticityCoordinates G { get; }
+
+ ///
+ /// Gets the chomaticity coordinates of the blue channel.
+ ///
+ public CieXyChromaticityCoordinates B { get; }
+
+ ///
+ /// Compares two objects for equality.
+ ///
+ ///
+ /// The on the left side of the operand.
+ ///
+ ///
+ /// The on the right side of the operand.
+ ///
+ ///
+ /// True if the current left is equal to the parameter; otherwise, false.
+ ///
+ public static bool operator ==(RgbPrimariesChromaticityCoordinates left, RgbPrimariesChromaticityCoordinates right)
+ {
+ return left.Equals(right);
+ }
+
+ ///
+ /// Compares two objects for inequality
+ ///
+ ///
+ /// The on the left side of the operand.
+ ///
+ ///
+ /// The on the right side of the operand.
+ ///
+ ///
+ /// True if the current left is unequal to the parameter; otherwise, false.
+ ///
+ public static bool operator !=(RgbPrimariesChromaticityCoordinates left, RgbPrimariesChromaticityCoordinates right)
+ {
+ return !left.Equals(right);
+ }
+
+ ///
+ public override bool Equals(object obj)
+ {
+ if (obj is RgbPrimariesChromaticityCoordinates)
+ {
+ return this.Equals((RgbPrimariesChromaticityCoordinates)obj);
+ }
+
+ return false;
+ }
+
+ ///
+ public bool Equals(RgbPrimariesChromaticityCoordinates other)
+ {
+ return this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B);
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ int hashCode = this.R.GetHashCode();
+ hashCode = (hashCode * 397) ^ this.G.GetHashCode();
+ hashCode = (hashCode * 397) ^ this.B.GetHashCode();
+ return hashCode;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/Rec2020Companding.cs b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/Rec2020Companding.cs
new file mode 100644
index 000000000..3f33beafb
--- /dev/null
+++ b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/Rec2020Companding.cs
@@ -0,0 +1,34 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Colors.Spaces.Conversion.Implementation.Rgb
+{
+ using System;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Implements Rec. 2020 companding function (for 12-bits).
+ ///
+ ///
+ ///
+ /// For 10-bits, companding is identical to
+ ///
+ public class Rec2020Companding : ICompanding
+ {
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public float Expand(float channel)
+ {
+ return channel < 0.08145F ? channel / 4.5F : (float)Math.Pow((channel + 0.0993) / 1.0993, 1 / 0.45);
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public float Compress(float channel)
+ {
+ return channel < 0.0181F ? 4500F * channel : (1.0993F * channel) - 0.0993F;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/Rec709Companding.cs b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/Rec709Companding.cs
new file mode 100644
index 000000000..2d19ce9b0
--- /dev/null
+++ b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/Rec709Companding.cs
@@ -0,0 +1,33 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Colors.Spaces.Conversion.Implementation.Rgb
+{
+ using System;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Implements the Rec. 709 companding function
+ ///
+ ///
+ /// http://en.wikipedia.org/wiki/Rec._709
+ ///
+ public class Rec709Companding : ICompanding
+ {
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public float Expand(float channel)
+ {
+ return channel < 0.081F ? channel / 4.5F : (float)Math.Pow((channel + 0.099) / 1.099, 1 / 0.45);
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public float Compress(float channel)
+ {
+ return channel < 0.018F ? 4500F * channel : (1.099F * channel) - 0.099F;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/RgbWorkingSpace.cs b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/RgbWorkingSpace.cs
new file mode 100644
index 000000000..426375436
--- /dev/null
+++ b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/RgbWorkingSpace.cs
@@ -0,0 +1,107 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Colors.Spaces.Conversion.Implementation.Rgb
+{
+ ///
+ /// Trivial implementation of
+ ///
+ public struct RgbWorkingSpace : IRgbWorkingSpace
+ {
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The reference white point.
+ /// The function pair for converting to and back.
+ /// The chromaticity of the rgb primaries.
+ public RgbWorkingSpace(CieXyz referenceWhite, ICompanding companding, RgbPrimariesChromaticityCoordinates chromaticityCoordinates)
+ {
+ this.WhitePoint = referenceWhite;
+ this.Companding = companding;
+ this.ChromaticityCoordinates = chromaticityCoordinates;
+ }
+
+ ///
+ /// Gets the reference white point
+ ///
+ public CieXyz WhitePoint { get; }
+
+ ///
+ /// Gets the function pair for converting to and back.
+ ///
+ public ICompanding Companding { get; }
+
+ ///
+ /// Gets the chromaticity of the rgb primaries.
+ ///
+ public RgbPrimariesChromaticityCoordinates ChromaticityCoordinates { get; }
+
+ ///
+ /// Compares two objects for equality.
+ ///
+ ///
+ /// The on the left side of the operand.
+ ///
+ ///
+ /// The on the right side of the operand.
+ ///
+ ///
+ /// True if the current left is equal to the parameter; otherwise, false.
+ ///
+ public static bool operator ==(RgbWorkingSpace left, RgbWorkingSpace right)
+ {
+ return Equals(left, right);
+ }
+
+ ///
+ /// Compares two objects for inequality
+ ///
+ ///
+ /// The on the left side of the operand.
+ ///
+ ///
+ /// The on the right side of the operand.
+ ///
+ ///
+ /// True if the current left is unequal to the parameter; otherwise, false.
+ ///
+ public static bool operator !=(RgbWorkingSpace left, RgbWorkingSpace right)
+ {
+ return !Equals(left, right);
+ }
+
+ ///
+ public override bool Equals(object obj)
+ {
+ if (obj is RgbWorkingSpace)
+ {
+ return this.Equals((RgbWorkingSpace)obj);
+ }
+
+ return false;
+ }
+
+ ///
+ public bool Equals(IRgbWorkingSpace other)
+ {
+ // TODO: Object.Equals for ICompanding will be slow.
+ return this.WhitePoint.Equals(other.WhitePoint)
+ && this.ChromaticityCoordinates.Equals(other.ChromaticityCoordinates)
+ && Equals(this.Companding, other.Companding);
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ int hashCode = this.WhitePoint.GetHashCode();
+ hashCode = (hashCode * 397) ^ this.ChromaticityCoordinates.GetHashCode();
+ hashCode = (hashCode * 397) ^ (this.Companding?.GetHashCode() ?? 0);
+ return hashCode;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/SRgbCompanding.cs b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/SRgbCompanding.cs
new file mode 100644
index 000000000..da30d19fa
--- /dev/null
+++ b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Rgb/SRgbCompanding.cs
@@ -0,0 +1,35 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Colors.Spaces.Conversion.Implementation.Rgb
+{
+ using System;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Implements sRGB companding
+ ///
+ ///
+ /// For more info see:
+ ///
+ ///
+ ///
+ public class SRgbCompanding : ICompanding
+ {
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public float Expand(float channel)
+ {
+ return channel <= 0.04045F ? channel / 12.92F : (float)Math.Pow((channel + 0.055) / 1.055, 2.4);
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public float Compress(float channel)
+ {
+ return channel <= 0.0031308F ? 12.92F * channel : (1.055F * (float)Math.Pow(channel, 0.416666666666667D)) - 0.055F;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/VonKriesChromaticAdaptation.cs b/src/ImageSharp/Colors/Spaces/Conversion/VonKriesChromaticAdaptation.cs
index 801f7cf15..d79a834db 100644
--- a/src/ImageSharp/Colors/Spaces/Conversion/VonKriesChromaticAdaptation.cs
+++ b/src/ImageSharp/Colors/Spaces/Conversion/VonKriesChromaticAdaptation.cs
@@ -3,12 +3,12 @@
// Licensed under the Apache License, Version 2.0.
//
-namespace ImageSharp.Colors.Conversion
+namespace ImageSharp.Colors.Spaces.Conversion
{
using System.Numerics;
- using Implementation;
- using Spaces;
+ using ImageSharp.Colors.Spaces;
+ using ImageSharp.Colors.Spaces.Conversion.Implementation.Lms;
///
/// Basic implementation of the von Kries chromatic adaptation model
diff --git a/src/ImageSharp/Colors/Spaces/ICompanding.cs b/src/ImageSharp/Colors/Spaces/ICompanding.cs
index 11e920f39..a2c8ca151 100644
--- a/src/ImageSharp/Colors/Spaces/ICompanding.cs
+++ b/src/ImageSharp/Colors/Spaces/ICompanding.cs
@@ -13,25 +13,25 @@ namespace ImageSharp.Colors.Spaces
public interface ICompanding
{
///
- /// Companded channel is made linear with respect to the energy.
+ /// Expands a companded channel to its linear equivalent with respect to the energy.
///
///
/// For more info see:
- /// http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html
+ ///
///
/// The channel value
/// The linear channel value
- float InverseCompanding(float channel);
+ float Expand(float channel);
///
- /// Uncompanded channel (linear) is made nonlinear (depends on the RGB color system).
+ /// Compresses an uncompanded channel (linear) to its nonlinear equivalent (depends on the RGB color system).
///
///
/// For more info see:
- /// http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html
+ ///
///
/// The channel value
/// The nonlinear channel value
- float Companding(float channel);
+ float Compress(float channel);
}
}
diff --git a/src/ImageSharp/Colors/Spaces/IRgbWorkingSpace.cs b/src/ImageSharp/Colors/Spaces/IRgbWorkingSpace.cs
index 76b70a911..68dfc6c06 100644
--- a/src/ImageSharp/Colors/Spaces/IRgbWorkingSpace.cs
+++ b/src/ImageSharp/Colors/Spaces/IRgbWorkingSpace.cs
@@ -5,27 +5,30 @@
namespace ImageSharp.Colors.Spaces
{
+ using System;
+
+ using ImageSharp.Colors.Spaces.Conversion.Implementation;
+ using ImageSharp.Colors.Spaces.Conversion.Implementation.Rgb;
+
///
/// Encasulates the RGB working color space
///
- public interface IRgbWorkingSpace
+ public interface IRgbWorkingSpace : IEquatable
{
///
/// Gets the reference white of the color space
///
CieXyz WhitePoint { get; }
- //
- // Gets Chromaticity coordinates of the primaries
- //
- // RGBPrimariesChromaticityCoordinates ChromaticityCoordinates { get; }
+ ///
+ /// Gets the chromaticity coordinates of the primaries
+ ///
+ RgbPrimariesChromaticityCoordinates ChromaticityCoordinates { get; }
///
- /// Gets the companding function associated with the RGB color system.
- /// Used for conversion to XYZ and backwards.
- /// See this for more information:
- /// http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html
- /// http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html
+ /// Gets the companding function associated with the RGB color system. Used for conversion to XYZ and backwards.
+ ///
+ ///
///
ICompanding Companding { get; }
}
diff --git a/src/ImageSharp/Colors/Spaces/RgbWorkingSpaces.cs b/src/ImageSharp/Colors/Spaces/RgbWorkingSpaces.cs
new file mode 100644
index 000000000..3fe560003
--- /dev/null
+++ b/src/ImageSharp/Colors/Spaces/RgbWorkingSpaces.cs
@@ -0,0 +1,117 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+// ReSharper disable InconsistentNaming
+namespace ImageSharp.Colors.Spaces
+{
+ using ImageSharp.Colors.Spaces.Conversion.Implementation.Rgb;
+
+ ///
+ /// Chromaticity coordinates taken from:
+ ///
+ ///
+ public static class RgbWorkingSpaces
+ {
+ ///
+ /// sRgb working space.
+ ///
+ ///
+ /// Uses proper companding function, according to:
+ ///
+ ///
+ public static readonly IRgbWorkingSpace SRgb = new RgbWorkingSpace(Illuminants.D65, new SRgbCompanding(), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.3000F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F)));
+
+ ///
+ /// Simplified sRgb working space (uses gamma companding instead of ).
+ /// See also .
+ ///
+ public static readonly IRgbWorkingSpace SRgbSimplified = new RgbWorkingSpace(Illuminants.D65, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.3000F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F)));
+
+ ///
+ /// Rec. 709 (ITU-R Recommendation BT.709) working space
+ ///
+ public static readonly IRgbWorkingSpace Rec709 = new RgbWorkingSpace(Illuminants.D65, new Rec709Companding(), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.64F, 0.33F), new CieXyChromaticityCoordinates(0.30F, 0.60F), new CieXyChromaticityCoordinates(0.15F, 0.06F)));
+
+ ///
+ /// Rec. 2020 (ITU-R Recommendation BT.2020F) working space
+ ///
+ public static readonly IRgbWorkingSpace Rec2020 = new RgbWorkingSpace(Illuminants.D65, new Rec2020Companding(), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.708F, 0.292F), new CieXyChromaticityCoordinates(0.170F, 0.797F), new CieXyChromaticityCoordinates(0.131F, 0.046F)));
+
+ ///
+ /// ECI Rgb v2 working space
+ ///
+ public static readonly IRgbWorkingSpace ECIRgbv2 = new RgbWorkingSpace(Illuminants.D50, new LCompanding(), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6700F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1400F, 0.0800F)));
+
+ ///
+ /// Adobe Rgb (1998) working space
+ ///
+ public static readonly IRgbWorkingSpace AdobeRgb1998 = new RgbWorkingSpace(Illuminants.D65, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F)));
+
+ ///
+ /// Apple sRgb working space
+ ///
+ public static readonly IRgbWorkingSpace ApplesRgb = new RgbWorkingSpace(Illuminants.D65, new GammaCompanding(1.8F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6250F, 0.3400F), new CieXyChromaticityCoordinates(0.2800F, 0.5950F), new CieXyChromaticityCoordinates(0.1550F, 0.0700F)));
+
+ ///
+ /// Best Rgb working space
+ ///
+ public static readonly IRgbWorkingSpace BestRgb = new RgbWorkingSpace(Illuminants.D50, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7347F, 0.2653F), new CieXyChromaticityCoordinates(0.2150F, 0.7750F), new CieXyChromaticityCoordinates(0.1300F, 0.0350F)));
+
+ ///
+ /// Beta Rgb working space
+ ///
+ public static readonly IRgbWorkingSpace BetaRgb = new RgbWorkingSpace(Illuminants.D50, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6888F, 0.3112F), new CieXyChromaticityCoordinates(0.1986F, 0.7551F), new CieXyChromaticityCoordinates(0.1265F, 0.0352F)));
+
+ ///
+ /// Bruce Rgb working space
+ ///
+ public static readonly IRgbWorkingSpace BruceRgb = new RgbWorkingSpace(Illuminants.D65, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2800F, 0.6500F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F)));
+
+ ///
+ /// CIE Rgb working space
+ ///
+ public static readonly IRgbWorkingSpace CIERgb = new RgbWorkingSpace(Illuminants.E, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.2740F, 0.7170F), new CieXyChromaticityCoordinates(0.1670F, 0.0090F)));
+
+ ///
+ /// ColorMatch Rgb working space
+ ///
+ public static readonly IRgbWorkingSpace ColorMatchRgb = new RgbWorkingSpace(Illuminants.D50, new GammaCompanding(1.8F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6300F, 0.3400F), new CieXyChromaticityCoordinates(0.2950F, 0.6050F), new CieXyChromaticityCoordinates(0.1500F, 0.0750F)));
+
+ ///
+ /// Don Rgb 4 working space
+ ///
+ public static readonly IRgbWorkingSpace DonRgb4 = new RgbWorkingSpace(Illuminants.D50, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6960F, 0.3000F), new CieXyChromaticityCoordinates(0.2150F, 0.7650F), new CieXyChromaticityCoordinates(0.1300F, 0.0350F)));
+
+ ///
+ /// Ekta Space PS5 working space
+ ///
+ public static readonly IRgbWorkingSpace EktaSpacePS5 = new RgbWorkingSpace(Illuminants.D50, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6950F, 0.3050F), new CieXyChromaticityCoordinates(0.2600F, 0.7000F), new CieXyChromaticityCoordinates(0.1100F, 0.0050F)));
+
+ ///
+ /// NTSC Rgb working space
+ ///
+ public static readonly IRgbWorkingSpace NTSCRgb = new RgbWorkingSpace(Illuminants.C, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6700F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1400F, 0.0800F)));
+
+ ///
+ /// PAL/SECAM Rgb working space
+ ///
+ public static readonly IRgbWorkingSpace PALSECAMRgb = new RgbWorkingSpace(Illuminants.D65, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2900F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F)));
+
+ ///
+ /// ProPhoto Rgb working space
+ ///
+ public static readonly IRgbWorkingSpace ProPhotoRgb = new RgbWorkingSpace(Illuminants.D50, new GammaCompanding(1.8F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7347F, 0.2653F), new CieXyChromaticityCoordinates(0.1596F, 0.8404F), new CieXyChromaticityCoordinates(0.0366F, 0.0001F)));
+
+ ///
+ /// SMPTE-C Rgb working space
+ ///
+ public static readonly IRgbWorkingSpace SMPTECRgb = new RgbWorkingSpace(Illuminants.D65, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6300F, 0.3400F), new CieXyChromaticityCoordinates(0.3100F, 0.5950F), new CieXyChromaticityCoordinates(0.1550F, 0.0700F)));
+
+ ///
+ /// Wide Gamut Rgb working space
+ ///
+ public static readonly IRgbWorkingSpace WideGamutRgb = new RgbWorkingSpace(Illuminants.D50, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.1150F, 0.8260F), new CieXyChromaticityCoordinates(0.1570F, 0.0180F)));
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceConvert.cs
index b3d08b56d..a18d5e703 100644
--- a/tests/ImageSharp.Benchmarks/Color/ColorspaceConvert.cs
+++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceConvert.cs
@@ -5,9 +5,10 @@
using Colourful;
using Colourful.Conversion;
- using ImageSharp.Colors.Conversion;
using ImageSharp.Colors.Spaces;
+ using ColorSpaceConverter = ImageSharp.Colors.Spaces.Conversion.ColorSpaceConverter;
+
public class ColorspaceConvert
{
private static readonly CieXyz CieXyz = new CieXyz(0.95047F, 1, 1.08883F);
diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndCieLabConversionTest.cs b/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndCieLabConversionTest.cs
index 958470f8a..55aec4db5 100644
--- a/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndCieLabConversionTest.cs
+++ b/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndCieLabConversionTest.cs
@@ -1,8 +1,9 @@
namespace ImageSharp.Tests
{
- using ImageSharp.Colors.Conversion;
using System.Collections.Generic;
using ImageSharp.Colors.Spaces;
+ using ImageSharp.Colors.Spaces.Conversion;
+
using Xunit;
///
diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndLmsConversionTest.cs b/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndLmsConversionTest.cs
index c0dbdf30e..a329d2d44 100644
--- a/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndLmsConversionTest.cs
+++ b/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndLmsConversionTest.cs
@@ -1,8 +1,9 @@
namespace ImageSharp.Tests
{
- using ImageSharp.Colors.Conversion;
using System.Collections.Generic;
using ImageSharp.Colors.Spaces;
+ using ImageSharp.Colors.Spaces.Conversion;
+
using Xunit;
///
diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/ColorConverterAdaptTest.cs b/tests/ImageSharp.Tests/Colors/Colorspaces/ColorConverterAdaptTest.cs
index b63374ce4..e28b451e0 100644
--- a/tests/ImageSharp.Tests/Colors/Colorspaces/ColorConverterAdaptTest.cs
+++ b/tests/ImageSharp.Tests/Colors/Colorspaces/ColorConverterAdaptTest.cs
@@ -1,10 +1,11 @@
-using ImageSharp.Colors.Conversion;
-using ImageSharp.Colors.Conversion.Implementation;
-using ImageSharp.Colors.Spaces;
-
namespace ImageSharp.Tests
{
using System.Collections.Generic;
+
+ using ImageSharp.Colors.Spaces;
+ using ImageSharp.Colors.Spaces.Conversion;
+ using ImageSharp.Colors.Spaces.Conversion.Implementation.Lms;
+
using Xunit;
public class ColorConverterAdaptTest