mirror of https://github.com/SixLabors/ImageSharp
23 changed files with 287 additions and 304 deletions
@ -0,0 +1,89 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Companding |
|||
{ |
|||
/// <summary>
|
|||
/// Implements sRGB companding
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// For more info see:
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
|
|||
/// </remarks>
|
|||
public static class SRgbCompanding |
|||
{ |
|||
/// <summary>
|
|||
/// Expands the companded vectors to their linear equivalents with respect to the energy.
|
|||
/// </summary>
|
|||
/// <param name="vectors">The span of vectors.</param>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static void Expand(Span<Vector4> vectors) |
|||
{ |
|||
ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); |
|||
|
|||
for (int i = 0; i < vectors.Length; i++) |
|||
{ |
|||
ref Vector4 v = ref Unsafe.Add(ref baseRef, i); |
|||
v.X = Expand(v.X); |
|||
v.Y = Expand(v.Y); |
|||
v.Z = Expand(v.Z); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compresses the uncompanded vectors to their nonlinear equivalents with respect to the energy.
|
|||
/// </summary>
|
|||
/// <param name="vectors">The span of vectors.</param>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static void Compress(Span<Vector4> vectors) |
|||
{ |
|||
ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); |
|||
|
|||
for (int i = 0; i < vectors.Length; i++) |
|||
{ |
|||
ref Vector4 v = ref Unsafe.Add(ref baseRef, i); |
|||
v.X = Compress(v.X); |
|||
v.Y = Compress(v.Y); |
|||
v.Z = Compress(v.Z); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Expands a companded vector to its linear equivalent with respect to the energy.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector.</param>
|
|||
/// <returns>The <see cref="Vector4"/> representing the linear channel values.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static Vector4 Expand(Vector4 vector) => new Vector4(Expand(vector.X), Expand(vector.Y), Expand(vector.Z), vector.W); |
|||
|
|||
/// <summary>
|
|||
/// Compresses an uncompanded vector (linear) to its nonlinear equivalent.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector.</param>
|
|||
/// <returns>The <see cref="Vector4"/> representing the nonlinear channel values.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static Vector4 Compress(Vector4 vector) => new Vector4(Compress(vector.X), Compress(vector.Y), Compress(vector.Z), vector.W); |
|||
|
|||
/// <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.04045F ? channel / 12.92F : MathF.Pow((channel + 0.055F) / 1.055F, 2.4F); |
|||
|
|||
/// <summary>
|
|||
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
|
|||
/// </summary>
|
|||
/// <param name="channel">The channel value.</param>
|
|||
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static float Compress(float channel) => channel <= 0.0031308F ? 12.92F * channel : (1.055F * MathF.Pow(channel, 0.416666666666667F)) - 0.055F; |
|||
} |
|||
} |
|||
@ -1,35 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation |
|||
{ |
|||
/// <summary>
|
|||
/// Implements sRGB companding
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// For more info see:
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
|
|||
/// </remarks>
|
|||
public static class SRgbCompanding |
|||
{ |
|||
/// <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.04045F ? channel / 12.92F : MathF.Pow((channel + 0.055F) / 1.055F, 2.4F); |
|||
|
|||
/// <summary>
|
|||
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
|
|||
/// </summary>
|
|||
/// <param name="channel">The channel value</param>
|
|||
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static float Compress(float channel) => channel <= 0.0031308F ? 12.92F * channel : (1.055F * MathF.Pow(channel, 0.416666666666667F)) - 0.055F; |
|||
} |
|||
} |
|||
@ -1,156 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// Extension methods for the <see cref="Vector4"/> struct.
|
|||
/// </summary>
|
|||
internal static class Vector4Extensions |
|||
{ |
|||
/// <summary>
|
|||
/// Pre-multiplies the "x", "y", "z" components of a vector by its "w" component leaving the "w" component intact.
|
|||
/// </summary>
|
|||
/// <param name="source">The <see cref="Vector4"/> to premultiply</param>
|
|||
/// <returns>The <see cref="Vector4"/></returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static Vector4 Premultiply(this Vector4 source) |
|||
{ |
|||
float w = source.W; |
|||
Vector4 premultiplied = source * w; |
|||
premultiplied.W = w; |
|||
return premultiplied; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Reverses the result of premultiplying a vector via <see cref="Premultiply(Vector4)"/>.
|
|||
/// </summary>
|
|||
/// <param name="source">The <see cref="Vector4"/> to premultiply</param>
|
|||
/// <returns>The <see cref="Vector4"/></returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static Vector4 UnPremultiply(this Vector4 source) |
|||
{ |
|||
float w = source.W; |
|||
Vector4 unpremultiplied = source / w; |
|||
unpremultiplied.W = w; |
|||
return unpremultiplied; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Bulk variant of <see cref="Premultiply(System.Numerics.Vector4)"/>
|
|||
/// </summary>
|
|||
/// <param name="vectors">The span of vectors</param>
|
|||
public static void Premultiply(Span<Vector4> vectors) |
|||
{ |
|||
// TODO: This method can be AVX2 optimized using Vector<float>
|
|||
ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); |
|||
|
|||
for (int i = 0; i < vectors.Length; i++) |
|||
{ |
|||
ref Vector4 v = ref Unsafe.Add(ref baseRef, i); |
|||
var s = new Vector4(v.W) |
|||
{ |
|||
W = 1 |
|||
}; |
|||
v *= s; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Bulk variant of <see cref="UnPremultiply(System.Numerics.Vector4)"/>
|
|||
/// </summary>
|
|||
/// <param name="vectors">The span of vectors</param>
|
|||
public static void UnPremultiply(Span<Vector4> vectors) |
|||
{ |
|||
// TODO: This method can be AVX2 optimized using Vector<float>
|
|||
ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); |
|||
|
|||
for (int i = 0; i < vectors.Length; i++) |
|||
{ |
|||
ref Vector4 v = ref Unsafe.Add(ref baseRef, i); |
|||
var s = new Vector4(1 / v.W) |
|||
{ |
|||
W = 1 |
|||
}; |
|||
v *= s; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compresses a linear color signal to its sRGB equivalent.
|
|||
/// <see href="http://www.4p8.com/eric.brasseur/gamma.html#formulas"/>
|
|||
/// <see href="http://entropymine.com/imageworsener/srgbformula/"/>
|
|||
/// </summary>
|
|||
/// <param name="linear">The <see cref="Vector4"/> whose signal to compress.</param>
|
|||
/// <returns>The <see cref="Vector4"/>.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static Vector4 Compress(this Vector4 linear) |
|||
{ |
|||
// TODO: Is there a faster way to do this?
|
|||
return new Vector4( |
|||
SRgbCompanding.Compress(linear.X), |
|||
SRgbCompanding.Compress(linear.Y), |
|||
SRgbCompanding.Compress(linear.Z), |
|||
linear.W); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Expands an sRGB color signal to its linear equivalent.
|
|||
/// <see href="http://www.4p8.com/eric.brasseur/gamma.html#formulas"/>
|
|||
/// <see href="http://entropymine.com/imageworsener/srgbformula/"/>
|
|||
/// </summary>
|
|||
/// <param name="gamma">The <see cref="Rgba32"/> whose signal to expand.</param>
|
|||
/// <returns>The <see cref="Vector4"/>.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static Vector4 Expand(this Vector4 gamma) |
|||
{ |
|||
// TODO: Is there a faster way to do this?
|
|||
return new Vector4( |
|||
SRgbCompanding.Expand(gamma.X), |
|||
SRgbCompanding.Expand(gamma.Y), |
|||
SRgbCompanding.Expand(gamma.Z), |
|||
gamma.W); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Bulk variant of <see cref="Compress(System.Numerics.Vector4)"/>
|
|||
/// </summary>
|
|||
/// <param name="vectors">The span of vectors</param>
|
|||
public static void Compress(Span<Vector4> vectors) |
|||
{ |
|||
ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); |
|||
|
|||
for (int i = 0; i < vectors.Length; i++) |
|||
{ |
|||
ref Vector4 v = ref Unsafe.Add(ref baseRef, i); |
|||
v.X = SRgbCompanding.Compress(v.X); |
|||
v.Y = SRgbCompanding.Compress(v.Y); |
|||
v.Z = SRgbCompanding.Compress(v.Z); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Bulk variant of <see cref="Expand(System.Numerics.Vector4)"/>
|
|||
/// </summary>
|
|||
/// <param name="vectors">The span of vectors</param>
|
|||
public static void Expand(Span<Vector4> vectors) |
|||
{ |
|||
ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); |
|||
|
|||
for (int i = 0; i < vectors.Length; i++) |
|||
{ |
|||
ref Vector4 v = ref Unsafe.Add(ref baseRef, i); |
|||
v.X = SRgbCompanding.Expand(v.X); |
|||
v.Y = SRgbCompanding.Expand(v.Y); |
|||
v.Z = SRgbCompanding.Expand(v.Z); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,86 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace SixLabors.ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// Utility methods for the <see cref="Vector4"/> struct.
|
|||
/// </summary>
|
|||
internal static class Vector4Utils |
|||
{ |
|||
/// <summary>
|
|||
/// Pre-multiplies the "x", "y", "z" components of a vector by its "w" component leaving the "w" component intact.
|
|||
/// </summary>
|
|||
/// <param name="source">The <see cref="Vector4"/> to premultiply</param>
|
|||
/// <returns>The <see cref="Vector4"/></returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static Vector4 Premultiply(Vector4 source) |
|||
{ |
|||
float w = source.W; |
|||
Vector4 premultiplied = source * w; |
|||
premultiplied.W = w; |
|||
return premultiplied; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Reverses the result of premultiplying a vector via <see cref="Premultiply(Vector4)"/>.
|
|||
/// </summary>
|
|||
/// <param name="source">The <see cref="Vector4"/> to premultiply</param>
|
|||
/// <returns>The <see cref="Vector4"/></returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static Vector4 UnPremultiply(Vector4 source) |
|||
{ |
|||
float w = source.W; |
|||
Vector4 unpremultiplied = source / w; |
|||
unpremultiplied.W = w; |
|||
return unpremultiplied; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Bulk variant of <see cref="Premultiply(Vector4)"/>
|
|||
/// </summary>
|
|||
/// <param name="vectors">The span of vectors</param>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static void Premultiply(Span<Vector4> vectors) |
|||
{ |
|||
// TODO: This method can be AVX2 optimized using Vector<float>
|
|||
ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); |
|||
|
|||
for (int i = 0; i < vectors.Length; i++) |
|||
{ |
|||
ref Vector4 v = ref Unsafe.Add(ref baseRef, i); |
|||
var s = new Vector4(v.W) |
|||
{ |
|||
W = 1 |
|||
}; |
|||
v *= s; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Bulk variant of <see cref="UnPremultiply(Vector4)"/>
|
|||
/// </summary>
|
|||
/// <param name="vectors">The span of vectors</param>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static void UnPremultiply(Span<Vector4> vectors) |
|||
{ |
|||
// TODO: This method can be AVX2 optimized using Vector<float>
|
|||
ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); |
|||
|
|||
for (int i = 0; i < vectors.Length; i++) |
|||
{ |
|||
ref Vector4 v = ref Unsafe.Add(ref baseRef, i); |
|||
var s = new Vector4(1 / v.W) |
|||
{ |
|||
W = 1 |
|||
}; |
|||
v *= s; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,74 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Linq; |
|||
using System.Numerics; |
|||
|
|||
using Xunit; |
|||
|
|||
namespace SixLabors.ImageSharp.Tests.Helpers |
|||
{ |
|||
public class Vector4ExtensionsTests |
|||
{ |
|||
[Theory] |
|||
[InlineData(0)] |
|||
[InlineData(1)] |
|||
[InlineData(30)] |
|||
public void Premultiply_VectorSpan(int length) |
|||
{ |
|||
var rnd = new Random(42); |
|||
Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); |
|||
Vector4[] expected = source.Select(v => v.Premultiply()).ToArray(); |
|||
|
|||
Vector4Extensions.Premultiply(source); |
|||
|
|||
Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(0)] |
|||
[InlineData(1)] |
|||
[InlineData(30)] |
|||
public void UnPremultiply_VectorSpan(int length) |
|||
{ |
|||
var rnd = new Random(42); |
|||
Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); |
|||
Vector4[] expected = source.Select(v => v.UnPremultiply()).ToArray(); |
|||
|
|||
Vector4Extensions.UnPremultiply(source); |
|||
|
|||
Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(0)] |
|||
[InlineData(1)] |
|||
[InlineData(30)] |
|||
public void Expand_VectorSpan(int length) |
|||
{ |
|||
var rnd = new Random(42); |
|||
Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); |
|||
Vector4[] expected = source.Select(v => v.Expand()).ToArray(); |
|||
|
|||
Vector4Extensions.Expand(source); |
|||
|
|||
Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(0)] |
|||
[InlineData(1)] |
|||
[InlineData(30)] |
|||
public void Compress_VectorSpan(int length) |
|||
{ |
|||
var rnd = new Random(42); |
|||
Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); |
|||
Vector4[] expected = source.Select(v => v.Compress()).ToArray(); |
|||
|
|||
Vector4Extensions.Compress(source); |
|||
|
|||
Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Linq; |
|||
using System.Numerics; |
|||
|
|||
using Xunit; |
|||
|
|||
namespace SixLabors.ImageSharp.Tests.Helpers |
|||
{ |
|||
public class Vector4UtilsTests |
|||
{ |
|||
[Theory] |
|||
[InlineData(0)] |
|||
[InlineData(1)] |
|||
[InlineData(30)] |
|||
public void Premultiply_VectorSpan(int length) |
|||
{ |
|||
var rnd = new Random(42); |
|||
Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); |
|||
Vector4[] expected = source.Select(v => Vector4Utils.Premultiply(v)).ToArray(); |
|||
|
|||
Vector4Utils.Premultiply(source); |
|||
|
|||
Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(0)] |
|||
[InlineData(1)] |
|||
[InlineData(30)] |
|||
public void UnPremultiply_VectorSpan(int length) |
|||
{ |
|||
var rnd = new Random(42); |
|||
Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); |
|||
Vector4[] expected = source.Select(v => Vector4Utils.UnPremultiply(v)).ToArray(); |
|||
|
|||
Vector4Utils.UnPremultiply(source); |
|||
|
|||
Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue