Browse Source

Move compaing classes and migrate vector code to srgbcompaning

af/merge-core
James Jackson-South 7 years ago
parent
commit
b0b2d55cbb
  1. 2
      src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs
  2. 3
      src/ImageSharp/ColorSpaces/Companding/LCompanding.cs
  3. 2
      src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs
  4. 2
      src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs
  5. 89
      src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs
  6. 1
      src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs
  7. 1
      src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs
  8. 1
      src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs
  9. 1
      src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs
  10. 35
      src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbCompanding.cs
  11. 1
      src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs
  12. 1
      src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs
  13. 156
      src/ImageSharp/Common/Extensions/Vector4Extensions.cs
  14. 86
      src/ImageSharp/Common/Helpers/Vector4Utils.cs
  15. 4
      src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs
  16. 7
      src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs
  17. 4
      src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs
  18. 7
      src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs
  19. 12
      src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs
  20. 9
      src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs
  21. 49
      tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs
  22. 74
      tests/ImageSharp.Tests/Helpers/Vector4ExtensionsTests.cs
  23. 44
      tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaCompanding.cs → src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs

@ -4,7 +4,7 @@
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
namespace SixLabors.ImageSharp.ColorSpaces.Companding
{
/// <summary>
/// Implements gamma companding

3
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LCompanding.cs → src/ImageSharp/ColorSpaces/Companding/LCompanding.cs

@ -3,8 +3,9 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
namespace SixLabors.ImageSharp.ColorSpaces.Companding
{
/// <summary>
/// Implements L* companding

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020Companding.cs → src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs

@ -4,7 +4,7 @@
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
namespace SixLabors.ImageSharp.ColorSpaces.Companding
{
/// <summary>
/// Implements Rec. 2020 companding function (for 12-bits).

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709Companding.cs → src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs

@ -4,7 +4,7 @@
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
namespace SixLabors.ImageSharp.ColorSpaces.Companding
{
/// <summary>
/// Implements the Rec. 709 companding function.

89
src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs

@ -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
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
{

1
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
{

1
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
{

1
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
{

35
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbCompanding.cs

@ -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
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
{

1
src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.ColorSpaces.Companding;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation;
// ReSharper disable InconsistentNaming

156
src/ImageSharp/Common/Extensions/Vector4Extensions.cs

@ -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);
}
}
}
}

86
src/ImageSharp/Common/Helpers/Vector4Utils.cs

@ -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;
}
}
}
}

4
src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs

@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
int offsetX = x + fxr;
offsetX = offsetX.Clamp(0, maxX);
Vector4 currentColor = sourceOffsetRow[offsetX].ToVector4().Premultiply();
Vector4 currentColor = Vector4Utils.Premultiply(sourceOffsetRow[offsetX].ToVector4());
if (fy < kernelXHeight)
{
@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
ref TPixel pixel = ref targetRow[x];
pixel.PackFromVector4(
new Vector4(red, green, blue, sourceRow[x].ToVector4().W).UnPremultiply());
Vector4Utils.UnPremultiply(new Vector4(red, green, blue, sourceRow[x].ToVector4().W)));
}
}
});

7
src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs

@ -3,14 +3,11 @@
using System;
using System.Numerics;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.ParallelUtils;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
@ -114,13 +111,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
offsetX = offsetX.Clamp(0, maxX);
Vector4 currentColor = row[offsetX].ToVector4().Premultiply();
Vector4 currentColor = Vector4Utils.Premultiply(row[offsetX].ToVector4());
destination += kernel[fy, fx] * currentColor;
}
}
ref TPixel pixel = ref targetRow[x];
pixel.PackFromVector4(destination.UnPremultiply());
pixel.PackFromVector4(Vector4Utils.UnPremultiply(destination));
}
}
});

4
src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs

@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
offsetX = offsetX.Clamp(0, maxX);
Vector4 currentColor = sourceOffsetRow[offsetX].ToVector4().Premultiply();
Vector4 currentColor = Vector4Utils.Premultiply(sourceOffsetRow[offsetX].ToVector4());
currentColor *= this.KernelXY[fy, fx];
red += currentColor.X;
@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
ref TPixel pixel = ref targetRow[x];
pixel.PackFromVector4(
new Vector4(red, green, blue, sourceRow[x].ToVector4().W).UnPremultiply());
Vector4Utils.UnPremultiply(new Vector4(red, green, blue, sourceRow[x].ToVector4().W)));
}
}
});

7
src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs

@ -7,7 +7,6 @@ using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.ParallelUtils;
@ -207,18 +206,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
for (int xx = 0, i = minX; i <= maxX; i++, xx++)
{
float xWeight = Unsafe.Add(ref xSpanRef, xx);
var vector = source[i, j].ToVector4();
// Values are first premultiplied to prevent darkening of edge pixels
Vector4 multiplied = vector.Premultiply();
sum += multiplied * xWeight * yWeight;
sum += Vector4Utils.Premultiply(source[i, j].ToVector4()) * xWeight * yWeight;
}
}
ref TPixel dest = ref Unsafe.Add(ref destRowRef, x);
// Reverse the premultiplication
dest.PackFromVector4(sum.UnPremultiply());
dest.PackFromVector4(Vector4Utils.UnPremultiply(sum));
}
}
});

12
src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs

@ -7,7 +7,6 @@ using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.ParallelUtils;
@ -216,18 +215,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
for (int xx = 0, i = minX; i <= maxX; i++, xx++)
{
float xWeight = Unsafe.Add(ref xSpanRef, xx);
var vector = source[i, j].ToVector4();
// Values are first premultiplied to prevent darkening of edge pixels
Vector4 multiplied = vector.Premultiply();
sum += multiplied * xWeight * yWeight;
sum += Vector4Utils.Premultiply(source[i, j].ToVector4()) * xWeight * yWeight;
}
}
ref TPixel dest = ref Unsafe.Add(ref destRowRef, x);
// Reverse the premultiplication
dest.PackFromVector4(sum.UnPremultiply());
dest.PackFromVector4(Vector4Utils.UnPremultiply(sum));
}
}
});
@ -242,9 +239,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <returns>
/// The <see cref="Matrix4x4"/>.
/// </returns>
protected virtual Matrix4x4 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle)
{
return this.TransformMatrix;
}
protected virtual Matrix4x4 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle) => this.TransformMatrix;
}
}

9
src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs

@ -9,6 +9,7 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.ColorSpaces.Companding;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.ParallelUtils;
using SixLabors.ImageSharp.PixelFormats;
@ -257,13 +258,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
Span<Vector4> tempRowSpan = tempRowBuffer.Span;
PixelOperations<TPixel>.Instance.ToVector4(sourceRow, tempRowSpan, sourceRow.Length);
Vector4Extensions.Premultiply(tempRowSpan);
Vector4Utils.Premultiply(tempRowSpan);
ref Vector4 firstPassBaseRef = ref firstPassPixelsTransposed.Span[y];
if (this.Compand)
{
Vector4Extensions.Expand(tempRowSpan);
SRgbCompanding.Expand(tempRowSpan);
}
for (int x = minX; x < maxX; x++)
@ -300,11 +301,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
Unsafe.Add(ref tempRowBase, x) = window.Convolve(firstPassColumn, sourceY);
}
Vector4Extensions.UnPremultiply(tempRowSpan);
Vector4Utils.UnPremultiply(tempRowSpan);
if (this.Compand)
{
Vector4Extensions.Compress(tempRowSpan);
SRgbCompanding.Compress(tempRowSpan);
}
Span<TPixel> targetRowSpan = destination.GetPixelRowSpan(y);

49
tests/ImageSharp.Tests/Colorspaces/Conversion/CompandingTests.cs → tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs

@ -1,10 +1,13 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation;
using System;
using System.Linq;
using System.Numerics;
using SixLabors.ImageSharp.ColorSpaces.Companding;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion
namespace SixLabors.ImageSharp.Tests.Colorspaces.Companding
{
/// <summary>
/// Tests various companding algorithms. Numbers are hand calculated from formulas online.
@ -16,7 +19,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion
private static readonly ApproximateFloatComparer FloatComparer = new ApproximateFloatComparer(.00001F);
[Fact]
public void Rec2020CompandingIsCorrect()
public void Rec2020Companding_IsCorrect()
{
const float input = .667F;
float e = Rec2020Companding.Expand(input);
@ -25,7 +28,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion
}
[Fact]
public void Rec709CompandingIsCorrect()
public void Rec709Companding_IsCorrect()
{
const float input = .667F;
float e = Rec709Companding.Expand(input);
@ -34,7 +37,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion
}
[Fact]
public void SRgbCompandingIsCorrect()
public void SRgbCompanding_IsCorrect()
{
const float input = .667F;
float e = SRgbCompanding.Expand(input);
@ -42,8 +45,38 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion
CompandingIsCorrectImpl(e, c, .40242353F, .667F);
}
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(30)]
public void SRgbCompanding_Expand_VectorSpan(int length)
{
var rnd = new Random(42);
Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1);
Vector4[] expected = source.Select(v => SRgbCompanding.Expand(v)).ToArray();
SRgbCompanding.Expand(source);
Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f));
}
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(30)]
public void SRgbCompanding_Compress_VectorSpan(int length)
{
var rnd = new Random(42);
Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1);
Vector4[] expected = source.Select(v => SRgbCompanding.Compress(v)).ToArray();
SRgbCompanding.Compress(source);
Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f));
}
[Fact]
public void GammaCompandingIsCorrect()
public void GammaCompanding_IsCorrect()
{
const float gamma = 2.2F;
const float input = .667F;
@ -53,7 +86,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion
}
[Fact]
public void LCompandingIsCorrect()
public void LCompanding_IsCorrect()
{
const float input = .667F;
float e = LCompanding.Expand(input);
@ -67,4 +100,4 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion
Assert.Equal(compressed, c, FloatComparer);
}
}
}
}

74
tests/ImageSharp.Tests/Helpers/Vector4ExtensionsTests.cs

@ -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));
}
}
}

44
tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs

@ -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…
Cancel
Save