diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs
index c51a54a40..122952cae 100644
--- a/src/ImageSharp/Common/Helpers/ImageMaths.cs
+++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs
@@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp
/// The .
[MethodImpl(InliningOptions.ShortMethod)]
public static byte Get8BitBT709Luminance(byte r, byte g, byte b) =>
- (byte)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5f);
+ (byte)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5F);
///
/// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709.
@@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp
/// The .
[MethodImpl(InliningOptions.ShortMethod)]
public static ushort Get16BitBT709Luminance(ushort r, ushort g, ushort b) =>
- (ushort)((r * .2126F) + (g * .7152F) + (b * .0722F));
+ (ushort)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5F);
///
/// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709.
@@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp
/// The .
[MethodImpl(InliningOptions.ShortMethod)]
public static ushort Get16BitBT709Luminance(float r, float g, float b) =>
- (ushort)((r * .2126F) + (g * .7152F) + (b * .0722F));
+ (ushort)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5F);
///
/// Scales a value from a 16 bit to it's 8 bit equivalent.
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs
index 035d23854..b13c43827 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs
@@ -1,6 +1,7 @@
// 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;
@@ -236,7 +237,7 @@ namespace SixLabors.ImageSharp.PixelFormats
vector.Y,
vector.Z);
- this.A = (ushort)vector.W;
+ this.A = (ushort)MathF.Round(vector.W);
}
}
}
diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.L16OperationsTests.cs
similarity index 100%
rename from tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs
rename to tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.L16OperationsTests.cs
diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.L8OperationsTests.cs
similarity index 100%
rename from tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs
rename to tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.L8OperationsTests.cs
diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.La16OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.La16OperationsTests.cs
new file mode 100644
index 000000000..f03aa5587
--- /dev/null
+++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.La16OperationsTests.cs
@@ -0,0 +1,25 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using SixLabors.ImageSharp.PixelFormats;
+
+using Xunit;
+using Xunit.Abstractions;
+
+namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations
+{
+ public partial class PixelOperationsTests
+ {
+ public class La16OperationsTests : PixelOperationsTests
+ {
+ public La16OperationsTests(ITestOutputHelper output)
+ : base(output)
+ {
+ }
+
+ [Fact]
+ public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance);
+
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.La32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.La32OperationsTests.cs
new file mode 100644
index 000000000..2112a2fea
--- /dev/null
+++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.La32OperationsTests.cs
@@ -0,0 +1,25 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using SixLabors.ImageSharp.PixelFormats;
+
+using Xunit;
+using Xunit.Abstractions;
+
+namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations
+{
+ public partial class PixelOperationsTests
+ {
+ public class La32OperationsTests : PixelOperationsTests
+ {
+ public La32OperationsTests(ITestOutputHelper output)
+ : base(output)
+ {
+ }
+
+ [Fact]
+ public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance);
+
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs
index 0f5b5838e..ef2531060 100644
--- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs
+++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs
@@ -617,6 +617,188 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations
);
}
+ [Theory]
+ [MemberData(nameof(ArraySizesData))]
+ public void FromL8(int count)
+ {
+ byte[] sourceBytes = CreateByteTestData(count);
+ L8[] source = sourceBytes.Select(b => new L8(b)).ToArray();
+ var expected = new TPixel[count];
+
+
+ for (int i = 0; i < count; i++)
+ {
+ expected[i].FromL8(source[i]);
+ }
+
+ TestOperation(
+ source,
+ expected,
+ (s, d) => Operations.FromL8(this.Configuration, s, d.GetSpan())
+ );
+ }
+
+ [Theory]
+ [MemberData(nameof(ArraySizesData))]
+ public void ToL8(int count)
+ {
+ TPixel[] source = CreatePixelTestData(count);
+ var expected = new L8[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ expected[i].FromScaledVector4(source[i].ToScaledVector4());
+ }
+
+ TestOperation(
+ source,
+ expected,
+ (s, d) => Operations.ToL8(this.Configuration, s, d.GetSpan())
+ );
+ }
+
+ [Theory]
+ [MemberData(nameof(ArraySizesData))]
+ public void FromL16(int count)
+ {
+ L16[] source = CreateVector4TestData(count).Select(v =>
+ {
+ L16 g = default;
+ g.FromVector4(v);
+ return g;
+ }).ToArray();
+
+ var expected = new TPixel[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ expected[i].FromL16(source[i]);
+ }
+
+ TestOperation(
+ source,
+ expected,
+ (s, d) => Operations.FromL16(this.Configuration, s, d.GetSpan())
+ );
+ }
+
+ [Theory]
+ [MemberData(nameof(ArraySizesData))]
+ public void ToL16(int count)
+ {
+ TPixel[] source = CreatePixelTestData(count);
+ var expected = new L16[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ expected[i].FromScaledVector4(source[i].ToScaledVector4());
+ }
+
+ TestOperation(
+ source,
+ expected,
+ (s, d) => Operations.ToL16(this.Configuration, s, d.GetSpan())
+ );
+ }
+
+ [Theory]
+ [MemberData(nameof(ArraySizesData))]
+ public void FromLa16Bytes(int count)
+ {
+ int size = Unsafe.SizeOf();
+ byte[] source = CreateByteTestData(count * size);
+ var expected = new TPixel[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ int offset = i * size;
+
+ La16 la = MemoryMarshal.Cast(source.AsSpan().Slice(offset, size))[0];
+ expected[i].FromLa16(la);
+ }
+
+ TestOperation(
+ source,
+ expected,
+ (s, d) => Operations.FromLa16Bytes(this.Configuration, s, d.GetSpan(), count)
+ );
+ }
+
+ [Theory]
+ [MemberData(nameof(ArraySizesData))]
+ public void ToLa16Bytes(int count)
+ {
+ int size = Unsafe.SizeOf();
+ TPixel[] source = CreatePixelTestData(count);
+ var expected = new byte[count * size];
+ La16 la = default;
+
+ for (int i = 0; i < count; i++)
+ {
+ int offset = i * size;
+ la.FromScaledVector4(source[i].ToScaledVector4());
+ OctetBytes bytes = Unsafe.As(ref la);
+ expected[offset] = bytes[0];
+ expected[offset + 1] = bytes[1];
+ }
+
+ TestOperation(
+ source,
+ expected,
+ (s, d) => Operations.ToLa16Bytes(this.Configuration, s, d.GetSpan(), count)
+ );
+ }
+
+ [Theory]
+ [MemberData(nameof(ArraySizesData))]
+ public void FromLa32Bytes(int count)
+ {
+ int size = Unsafe.SizeOf();
+ byte[] source = CreateByteTestData(count * size);
+ var expected = new TPixel[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ int offset = i * size;
+
+ La32 la = MemoryMarshal.Cast(source.AsSpan().Slice(offset, size))[0];
+ expected[i].FromLa32(la);
+ }
+
+ TestOperation(
+ source,
+ expected,
+ (s, d) => Operations.FromLa32Bytes(this.Configuration, s, d.GetSpan(), count)
+ );
+ }
+
+ [Theory]
+ [MemberData(nameof(ArraySizesData))]
+ public void ToLa32Bytes(int count)
+ {
+ var size = Unsafe.SizeOf();
+ TPixel[] source = CreatePixelTestData(count);
+ var expected = new byte[count * size];
+ La32 la = default;
+
+ for (int i = 0; i < count; i++)
+ {
+ int offset = i * size;
+ la.FromScaledVector4(source[i].ToScaledVector4());
+ OctetBytes bytes = Unsafe.As(ref la);
+ expected[offset] = bytes[0];
+ expected[offset + 1] = bytes[1];
+ expected[offset + 2] = bytes[2];
+ expected[offset + 3] = bytes[3];
+ }
+
+ TestOperation(
+ source,
+ expected,
+ (s, d) => Operations.ToLa32Bytes(this.Configuration, s, d.GetSpan(), count)
+ );
+ }
+
[Theory]
[MemberData(nameof(ArraySizesData))]
public void FromRgb24Bytes(int count)
@@ -808,91 +990,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations
);
}
-
- [Theory]
- [MemberData(nameof(ArraySizesData))]
- public void FromL8(int count)
- {
- byte[] sourceBytes = CreateByteTestData(count);
- L8[] source = sourceBytes.Select(b => new L8(b)).ToArray();
- var expected = new TPixel[count];
-
-
- for (int i = 0; i < count; i++)
- {
- expected[i].FromL8(source[i]);
- }
-
- TestOperation(
- source,
- expected,
- (s, d) => Operations.FromL8(this.Configuration, s, d.GetSpan())
- );
- }
-
- [Theory]
- [MemberData(nameof(ArraySizesData))]
- public void ToL8(int count)
- {
- TPixel[] source = CreatePixelTestData(count);
- var expected = new L8[count];
-
- for (int i = 0; i < count; i++)
- {
- expected[i].FromScaledVector4(source[i].ToScaledVector4());
- }
-
- TestOperation(
- source,
- expected,
- (s, d) => Operations.ToL8(this.Configuration, s, d.GetSpan())
- );
- }
-
- [Theory]
- [MemberData(nameof(ArraySizesData))]
- public void FromL16(int count)
- {
- L16[] source = CreateVector4TestData(count).Select(v =>
- {
- L16 g = default;
- g.FromVector4(v);
- return g;
- }).ToArray();
-
- var expected = new TPixel[count];
-
- for (int i = 0; i < count; i++)
- {
- expected[i].FromL16(source[i]);
- }
-
- TestOperation(
- source,
- expected,
- (s, d) => Operations.FromL16(this.Configuration, s, d.GetSpan())
- );
- }
-
- [Theory]
- [MemberData(nameof(ArraySizesData))]
- public void ToL16(int count)
- {
- TPixel[] source = CreatePixelTestData(count);
- var expected = new L16[count];
-
- for (int i = 0; i < count; i++)
- {
- expected[i].FromScaledVector4(source[i].ToScaledVector4());
- }
-
- TestOperation(
- source,
- expected,
- (s, d) => Operations.ToL16(this.Configuration, s, d.GetSpan())
- );
- }
-
public delegate void RefAction(ref T1 arg1);
internal static Vector4[] CreateExpectedVector4Data(TPixel[] source, RefAction vectorModifier = null)
@@ -1064,18 +1161,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations
// ReSharper restore PossibleNullReferenceException
}
}
- else if (typeof(TDest) == typeof(L16))
- {
- // Minor difference is tolerated for 16 bit pixel values
- Span expected = MemoryMarshal.Cast(this.ExpectedDestBuffer.AsSpan());
- Span actual = MemoryMarshal.Cast(this.ActualDestBuffer.GetSpan());
-
- for (int i = 0; i < count; i++)
- {
- int difference = expected[i].PackedValue - actual[i].PackedValue;
- Assert.True(Math.Abs(difference) < 2);
- }
- }
else
{
Span expected = this.ExpectedDestBuffer.AsSpan();