Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace SixLabors.ImageSharp.ColorSpaces
{
/// <summary>
/// Represents the coordinates of CIEXY chromaticity space
/// Represents the coordinates of CIEXY chromaticity space.
/// </summary>
public readonly struct CieXyChromaticityCoordinates : IEquatable<CieXyChromaticityCoordinates>
{
Expand Down
2 changes: 1 addition & 1 deletion src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace SixLabors.ImageSharp.ColorSpaces.Companding
{
/// <summary>
/// Implements gamma companding
/// Implements gamma companding.
/// </summary>
/// <remarks>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
Expand Down
6 changes: 3 additions & 3 deletions src/ImageSharp/ColorSpaces/Companding/LCompanding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace SixLabors.ImageSharp.ColorSpaces.Companding
{
/// <summary>
/// Implements L* companding
/// Implements L* companding.
/// </summary>
/// <remarks>
/// For more info see:
Expand All @@ -24,7 +24,7 @@ public static class LCompanding
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Expand(float channel)
=> channel <= 0.08 ? 100 * channel / CieConstants.Kappa : ImageMaths.Pow3((channel + 0.16F) / 1.16F);
=> channel <= 0.08F ? (100F * channel) / CieConstants.Kappa : ImageMaths.Pow3((channel + 0.16F) / 1.16F);

/// <summary>
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
Expand All @@ -33,6 +33,6 @@ public static float Expand(float channel)
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Compress(float channel)
=> channel <= CieConstants.Epsilon ? channel * CieConstants.Kappa / 100F : MathF.Pow(1.16F * channel, 0.3333333F) - 0.16F;
=> channel <= CieConstants.Epsilon ? (channel * CieConstants.Kappa) / 100F : (1.16F * MathF.Pow(channel, 0.3333333F)) - 0.16F;
}
}
13 changes: 9 additions & 4 deletions src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,27 @@
namespace SixLabors.ImageSharp.ColorSpaces.Companding
{
/// <summary>
/// Implements Rec. 2020 companding function (for 12-bits).
/// Implements Rec. 2020 companding function.
/// </summary>
/// <remarks>
/// <see href="http://en.wikipedia.org/wiki/Rec._2020"/>
/// For 10-bits, companding is identical to <see cref="Rec709Companding"/>
/// </remarks>
public static class Rec2020Companding
{
private const float Alpha = 1.09929682680944F;
private const float AlphaMinusOne = Alpha - 1F;
private const float Beta = 0.018053968510807F;
private const float InverseBeta = Beta * 4.5F;
private const float Epsilon = 1 / 0.45F;

/// <summary>
/// Expands a companded channel to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Expand(float channel)
=> channel < 0.08145F ? channel / 4.5F : MathF.Pow((channel + 0.0993F) / 1.0993F, 2.222222F);
=> channel < InverseBeta ? channel / 4.5F : MathF.Pow((channel + AlphaMinusOne) / Alpha, Epsilon);

/// <summary>
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
Expand All @@ -31,6 +36,6 @@ public static float Expand(float channel)
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Compress(float channel)
=> channel < 0.0181F ? 4500F * channel : (1.0993F * channel) - 0.0993F;
=> channel < Beta ? 4.5F * channel : (Alpha * MathF.Pow(channel, 0.45F)) - AlphaMinusOne;
}
}
6 changes: 4 additions & 2 deletions src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
/// </remarks>
public static class Rec709Companding
{
private const float Epsilon = 1 / 0.45F;

/// <summary>
/// Expands a companded channel to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Expand(float channel)
=> channel < 0.081F ? channel / 4.5F : MathF.Pow((channel + 0.099F) / 1.099F, 2.222222F);
=> channel < 0.081F ? channel / 4.5F : MathF.Pow((channel + 0.099F) / 1.099F, Epsilon);

/// <summary>
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
Expand All @@ -30,6 +32,6 @@ public static float Expand(float channel)
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Compress(float channel)
=> channel < 0.018F ? 4500F * channel : (1.099F * channel) - 0.099F;
=> channel < 0.018F ? 4.5F * channel : (1.099F * MathF.Pow(channel, 0.45F)) - 0.099F;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@ public partial class ColorSpaceConverter
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in CieLab color)
{
// Adaptation
CieLab adapted = this.Adapt(color);

// Conversion
return CieLabToCieLchConverter.Convert(adapted);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
{
/// <summary>
/// Color converter between CIE XYZ and CIE xyY
/// Color converter between CIE XYZ and CIE xyY.
/// <see href="http://www.brucelindbloom.com/"/> for formulas.
/// </summary>
internal sealed class CieXyzAndCieXyyConverter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,28 @@ public CieXyzToLinearRgbConverter()
public CieXyzToLinearRgbConverter(RgbWorkingSpaceBase workingSpace)
{
this.TargetWorkingSpace = workingSpace;
this.conversionMatrix = GetRgbToCieXyzMatrix(workingSpace);

// Gets the inverted Rgb -> Xyz matrix
Matrix4x4.Invert(GetRgbToCieXyzMatrix(workingSpace), out Matrix4x4 inverted);

this.conversionMatrix = inverted;
}

/// <summary>
/// Gets the target working space
/// Gets the target working space.
/// </summary>
public RgbWorkingSpaceBase TargetWorkingSpace { get; }

/// <summary>
/// Performs the conversion from the <see cref="CieXyz"/> input to an instance of <see cref="LinearRgb"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
/// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public LinearRgb Convert(in CieXyz input)
{
Matrix4x4.Invert(this.conversionMatrix, out Matrix4x4 inverted);
var vector = Vector3.Transform(input.ToVector3(), inverted);
var vector = Vector3.Transform(input.ToVector3(), this.conversionMatrix);

return new LinearRgb(vector, this.TargetWorkingSpace);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
{
/// <summary>
/// Color converter between <see cref="Cmyk"/> and <see cref="Rgb"/>
/// Color converter between <see cref="Cmyk"/> and <see cref="Rgb"/>.
/// </summary>
internal sealed class CmykAndRgbConverter
{
Expand All @@ -28,7 +28,7 @@ public Rgb Convert(in Cmyk input)
/// Performs the conversion from the <see cref="Rgb"/> input to an instance of <see cref="Cmyk"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
/// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public Cmyk Convert(in Rgb input)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,23 @@
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
{
/// <summary>
/// Color converter between <see cref="LinearRgb"/> and <see cref="Rgb"/>
/// Color converter between <see cref="LinearRgb"/> and <see cref="Rgb"/>.
/// </summary>
internal sealed class LinearRgbToRgbConverter
{
/// <summary>
/// Performs the conversion from the <see cref="LinearRgb"/> input to an instance of <see cref="Rgb"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
/// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public Rgb Convert(in LinearRgb input)
{
var vector = input.ToVector3();
vector.X = input.WorkingSpace.Compress(vector.X);
vector.Y = input.WorkingSpace.Compress(vector.Y);
vector.Z = input.WorkingSpace.Compress(vector.Z);

return new Rgb(vector, input.WorkingSpace);
return new Rgb(
r: input.WorkingSpace.Compress(input.R),
g: input.WorkingSpace.Compress(input.G),
b: input.WorkingSpace.Compress(input.B),
workingSpace: input.WorkingSpace);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,23 @@
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
{
/// <summary>
/// Color converter between Rgb and LinearRgb
/// Color converter between Rgb and LinearRgb.
/// </summary>
internal class RgbToLinearRgbConverter
{
/// <summary>
/// Performs the conversion from the <see cref="Rgb"/> input to an instance of <see cref="LinearRgb"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
/// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public LinearRgb Convert(in Rgb input)
{
var vector = input.ToVector3();
vector.X = input.WorkingSpace.Expand(vector.X);
vector.Y = input.WorkingSpace.Expand(vector.Y);
vector.Z = input.WorkingSpace.Expand(vector.Z);

return new LinearRgb(vector, input.WorkingSpace);
return new LinearRgb(
r: input.WorkingSpace.Expand(input.R),
g: input.WorkingSpace.Expand(input.G),
b: input.WorkingSpace.Expand(input.B),
workingSpace: input.WorkingSpace);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ internal sealed class YCbCrAndRgbConverter
/// Performs the conversion from the <see cref="YCbCr"/> input to an instance of <see cref="Rgb"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
/// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public Rgb Convert(in YCbCr input)
{
Expand All @@ -38,7 +38,7 @@ public Rgb Convert(in YCbCr input)
/// Performs the conversion from the <see cref="Rgb"/> input to an instance of <see cref="YCbCr"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
/// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public YCbCr Convert(in Rgb input)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
/// <summary>
/// The gamma working space.
/// </summary>
public class GammaWorkingSpace : RgbWorkingSpaceBase
public sealed class GammaWorkingSpace : RgbWorkingSpaceBase
{
/// <summary>
/// Initializes a new instance of the <see cref="GammaWorkingSpace" /> class.
Expand Down
15 changes: 6 additions & 9 deletions tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@
// Licensed under the Apache License, Version 2.0.

using System;
using System.Linq;
using System.Numerics;
using SixLabors.ImageSharp.ColorSpaces.Companding;
using Xunit;

namespace SixLabors.ImageSharp.Tests.Colorspaces.Companding
{
/// <summary>
/// Tests various companding algorithms. Numbers are hand calculated from formulas online.
/// TODO: Oddly the formula for converting to/from Rec 2020 and 709 from Wikipedia seems to cause the value to
/// fail a round trip. They're large spaces so this is a surprise. More reading required!!
/// Tests various companding algorithms. Expanded numbers are hand calculated from formulas online.
/// </summary>
public class CompandingTests
{
Expand All @@ -24,7 +21,7 @@ public void Rec2020Companding_IsCorrect()
const float input = .667F;
float e = Rec2020Companding.Expand(input);
float c = Rec2020Companding.Compress(e);
CompandingIsCorrectImpl(e, c, .4484759F, .3937096F);
CompandingIsCorrectImpl(e, c, .4484759F, input);
}

[Fact]
Expand All @@ -33,7 +30,7 @@ public void Rec709Companding_IsCorrect()
const float input = .667F;
float e = Rec709Companding.Expand(input);
float c = Rec709Companding.Compress(e);
CompandingIsCorrectImpl(e, c, .4483577F, .3937451F);
CompandingIsCorrectImpl(e, c, .4483577F, input);
}

[Fact]
Expand All @@ -42,7 +39,7 @@ public void SRgbCompanding_IsCorrect()
const float input = .667F;
float e = SRgbCompanding.Expand(input);
float c = SRgbCompanding.Compress(e);
CompandingIsCorrectImpl(e, c, .40242353F, .667F);
CompandingIsCorrectImpl(e, c, .40242353F, input);
}

[Theory]
Expand Down Expand Up @@ -98,7 +95,7 @@ public void GammaCompanding_IsCorrect()
const float input = .667F;
float e = GammaCompanding.Expand(input, gamma);
float c = GammaCompanding.Compress(e, gamma);
CompandingIsCorrectImpl(e, c, .41027668F, .667F);
CompandingIsCorrectImpl(e, c, .41027668F, input);
}

[Fact]
Expand All @@ -107,7 +104,7 @@ public void LCompanding_IsCorrect()
const float input = .667F;
float e = LCompanding.Expand(input);
float c = LCompanding.Compress(e);
CompandingIsCorrectImpl(e, c, .36236193F, .58908917F);
CompandingIsCorrectImpl(e, c, .36236193F, input);
}

private static void CompandingIsCorrectImpl(float e, float c, float expanded, float compressed)
Expand Down