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