diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.cs b/src/ImageSharp/Common/Extensions/SimdUtils.cs deleted file mode 100644 index 7b77fefcac..0000000000 --- a/src/ImageSharp/Common/Extensions/SimdUtils.cs +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Diagnostics; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp -{ - /// - /// Various extension and utility methods for and utilizing SIMD capabilities - /// - internal static class SimdUtils - { - /// - /// Gets a value indicating whether the code is being executed on AVX2 CPU where both float and integer registers are of size 256 byte. - /// - public static bool IsAvx2CompatibleArchitecture => Vector.Count == 8 && Vector.Count == 8; - - internal static void GuardAvx2(string operation) - { - if (!IsAvx2CompatibleArchitecture) - { - throw new NotSupportedException($"{operation} is supported only on AVX2 CPU!"); - } - } - - /// - /// Transform all scalars in 'v' in a way that converting them to would have rounding semantics. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector4 PseudoRound(this Vector4 v) - { - var sign = Vector4.Clamp(v, new Vector4(-1), new Vector4(1)); - - return v + (sign * 0.5f); - } - - /// - /// Rounds all values in 'v' to the nearest integer following semantics. - /// Source: - /// - /// https://github.com/g-truc/glm/blob/master/glm/simd/common.h#L110 - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector FastRound(this Vector x) - { - Vector magic0 = new Vector(int.MinValue); // 0x80000000 - Vector sgn0 = Vector.AsVectorSingle(magic0); - Vector and0 = Vector.BitwiseAnd(sgn0, x); - Vector or0 = Vector.BitwiseOr(and0, new Vector(8388608.0f)); - Vector add0 = Vector.Add(x, or0); - Vector sub0 = Vector.Subtract(add0, or0); - return sub0; - } - - /// - /// Convert 'source.Length' values normalized into [0..1] from 'source' into 'dest' buffer of values. - /// The values gonna be scaled up into [0-255] and rounded. - /// Based on: - /// - /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions - /// - /// - internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan source, Span dest) - { - GuardAvx2(nameof(BulkConvertNormalizedFloatToByte)); - - DebugGuard.IsTrue((source.Length % Vector.Count) == 0, nameof(source), "source.Length should be divisable by Vector.Count!"); - - if (source.Length == 0) - { - return; - } - - ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - int n = source.Length / 8; - - Vector magick = new Vector(32768.0f); - Vector scale = new Vector(255f) / new Vector(256f); - - // need to copy to a temporary struct, because - // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) - // does not work. TODO: This might be a CoreClr bug, need to ask/report - var temp = default(Octet.OfUInt32); - ref Vector tempRef = ref Unsafe.As>(ref temp); - - for (int i = 0; i < n; i++) - { - // union { float f; uint32_t i; } u; - // u.f = 32768.0f + x * (255.0f / 256.0f); - // return (uint8_t)u.i; - Vector x = Unsafe.Add(ref srcBase, i); - x = (x * scale) + magick; - tempRef = x; - - ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); - d.LoadFrom(ref temp); - } - } - - /// - /// Same as but clamps overflown values before conversion. - /// - internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) - { - GuardAvx2(nameof(BulkConvertNormalizedFloatToByte)); - - DebugGuard.IsTrue((source.Length % Vector.Count) == 0, nameof(source), "source.Length should be divisable by Vector.Count!"); - - if (source.Length == 0) - { - return; - } - - ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - int n = source.Length / 8; - - Vector magick = new Vector(32768.0f); - Vector scale = new Vector(255f) / new Vector(256f); - - // need to copy to a temporary struct, because - // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) - // does not work. TODO: This might be a CoreClr bug, need to ask/report - var temp = default(Octet.OfUInt32); - ref Vector tempRef = ref Unsafe.As>(ref temp); - - for (int i = 0; i < n; i++) - { - // union { float f; uint32_t i; } u; - // u.f = 32768.0f + x * (255.0f / 256.0f); - // return (uint8_t)u.i; - Vector x = Unsafe.Add(ref srcBase, i); - x = Vector.Max(x, Vector.Zero); - x = Vector.Min(x, Vector.One); - - x = (x * scale) + magick; - tempRef = x; - - ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); - d.LoadFrom(ref temp); - } - } - - // TODO: Replace these with T4-d library level tuples! - internal static class Octet - { - [StructLayout(LayoutKind.Explicit, Size = 8 * sizeof(uint))] - public struct OfUInt32 - { - [FieldOffset(0 * sizeof(uint))] - public uint V0; - - [FieldOffset(1 * sizeof(uint))] - public uint V1; - - [FieldOffset(2 * sizeof(uint))] - public uint V2; - - [FieldOffset(3 * sizeof(uint))] - public uint V3; - - [FieldOffset(4 * sizeof(uint))] - public uint V4; - - [FieldOffset(5 * sizeof(uint))] - public uint V5; - - [FieldOffset(6 * sizeof(uint))] - public uint V6; - - [FieldOffset(7 * sizeof(uint))] - public uint V7; - - public override string ToString() - { - return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; - } - } - - [StructLayout(LayoutKind.Explicit, Size = 8)] - public struct OfByte - { - [FieldOffset(0)] - public byte V0; - - [FieldOffset(1)] - public byte V1; - - [FieldOffset(2)] - public byte V2; - - [FieldOffset(3)] - public byte V3; - - [FieldOffset(4)] - public byte V4; - - [FieldOffset(5)] - public byte V5; - - [FieldOffset(6)] - public byte V6; - - [FieldOffset(7)] - public byte V7; - - public override string ToString() - { - return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; - } - - public void LoadFrom(ref OfUInt32 i) - { - this.V0 = (byte)i.V0; - this.V1 = (byte)i.V1; - this.V2 = (byte)i.V2; - this.V3 = (byte)i.V3; - this.V4 = (byte)i.V4; - this.V5 = (byte)i.V5; - this.V6 = (byte)i.V6; - this.V7 = (byte)i.V7; - } - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 35769d96a7..1dc7405677 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -14,6 +14,73 @@ namespace SixLabors.ImageSharp /// internal static class ImageMaths { + /// + /// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static byte Get8BitBT709Luminance(byte r, byte g, byte b) => (byte)((r * .2126F) + (g * .7152F) + (b * .0722F)); + + /// + /// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static ushort Get16BitBT709Luminance(ushort r, ushort g, ushort b) => (ushort)((r * .2126F) + (g * .7152F) + (b * .0722F)); + + /// + /// Scales a value from a 16 bit to it's 8 bit equivalent. + /// + /// The 8 bit compoonent value. + /// The + [MethodImpl(InliningOptions.ShortMethod)] + public static byte DownScaleFrom16BitTo8Bit(ushort component) + { + // To scale to 8 bits From a 16-bit value V the required value (from the PNG specification) is: + // + // (V * 255) / 65535 + // + // This reduces to round(V / 257), or floor((V + 128.5)/257) + // + // Represent V as the two byte value vhi.vlo. Make a guess that the + // result is the top byte of V, vhi, then the correction to this value + // is: + // + // error = floor(((V-vhi.vhi) + 128.5) / 257) + // = floor(((vlo-vhi) + 128.5) / 257) + // + // This can be approximated using integer arithmetic (and a signed + // shift): + // + // error = (vlo-vhi+128) >> 8; + // + // The approximate differs from the exact answer only when (vlo-vhi) is + // 128; it then gives a correction of +1 when the exact correction is + // 0. This gives 128 errors. The exact answer (correct for all 16-bit + // input values) is: + // + // error = (vlo-vhi+128)*65535 >> 24; + // + // An alternative arithmetic calculation which also gives no errors is: + // + // (V * 255 + 32895) >> 16 + return (byte)(((component * 255) + 32895) >> 16); + } + + /// + /// Scales a value from an 8 bit to it's 16 bit equivalent. + /// + /// The 8 bit compoonent value. + /// The + [MethodImpl(InliningOptions.ShortMethod)] + public static ushort UpscaleFrom8BitTo16Bit(byte component) => (ushort)(component * 257); + /// /// Determine the Greatest CommonDivisor (GCD) of two numbers. /// @@ -39,6 +106,28 @@ namespace SixLabors.ImageSharp return (a / GreatestCommonDivisor(a, b)) * b; } + /// + /// Calculates % 4 + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static int Modulo4(int x) => x & 3; + + /// + /// Calculates % 8 + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static int Modulo8(int x) => x & 7; + + /// + /// Fast (x mod m) calculator, with the restriction that + /// should be power of 2. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static int ModuloP2(int x, int m) + { + return x & (m - 1); + } + /// /// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation. /// @@ -46,7 +135,7 @@ namespace SixLabors.ImageSharp /// A number that is greater than , but less than or equal to /// /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static int FastAbs(int x) { int y = x >> 31; @@ -58,7 +147,7 @@ namespace SixLabors.ImageSharp /// /// A single-precision floating-point number /// The number raised to the power of 2. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float Pow2(float x) => x * x; /// @@ -66,7 +155,7 @@ namespace SixLabors.ImageSharp /// /// A single-precision floating-point number /// The number raised to the power of 3. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float Pow3(float x) => x * x * x; /// @@ -77,7 +166,7 @@ namespace SixLabors.ImageSharp /// /// The /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static int GetBitsNeededForColorDepth(int colors) => Math.Max(1, (int)Math.Ceiling(Math.Log(colors, 2))); /// @@ -85,7 +174,7 @@ namespace SixLabors.ImageSharp /// /// The bit depth. /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static int GetColorCountForBitDepth(int bitDepth) => 1 << bitDepth; /// @@ -94,7 +183,7 @@ namespace SixLabors.ImageSharp /// The x provided to G(x). /// The spread of the blur. /// The Gaussian G(x) - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float Gaussian(float x, float sigma) { const float Numerator = 1.0f; @@ -117,7 +206,7 @@ namespace SixLabors.ImageSharp /// /// The sine cardinal of . /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float SinC(float f) { if (MathF.Abs(f) > Constants.Epsilon) @@ -140,7 +229,7 @@ namespace SixLabors.ImageSharp /// /// The . /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float GetBcValue(float x, float b, float c) { if (x < 0F) @@ -176,7 +265,7 @@ namespace SixLabors.ImageSharp /// /// The bounding . /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static Rectangle GetBoundingRectangle(Point topLeft, Point bottomRight) => new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y); /// diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs new file mode 100644 index 0000000000..0f1ce2ab6a --- /dev/null +++ b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs @@ -0,0 +1,215 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Diagnostics; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Tuples; + +// ReSharper disable MemberHidesStaticFromOuterClass +namespace SixLabors.ImageSharp +{ + internal static partial class SimdUtils + { + /// + /// Implementation with 256bit / AVX2 intrinsics NOT depending on newer API-s (Vector.Widen etc.) + /// + public static class BasicIntrinsics256 + { + public static bool IsAvailable { get; } = IsAvx2CompatibleArchitecture; + + /// + /// as many elements as possible, slicing them down (keeping the remainder). + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertByteToNormalizedFloatReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + + if (!IsAvailable) + { + return; + } + + int remainder = ImageMaths.Modulo8(source.Length); + int adjustedCount = source.Length - remainder; + + if (adjustedCount > 0) + { + BulkConvertByteToNormalizedFloat( + source.Slice(0, adjustedCount), + dest.Slice(0, adjustedCount)); + + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); + } + } + + /// + /// as many elements as possible, slicing them down (keeping the remainder). + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + + if (!IsAvailable) + { + return; + } + + int remainder = ImageMaths.Modulo8(source.Length); + int adjustedCount = source.Length - remainder; + + if (adjustedCount > 0) + { + BulkConvertNormalizedFloatToByteClampOverflows(source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount)); + + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); + } + } + + /// + /// SIMD optimized implementation for . + /// Works only with span Length divisible by 8. + /// Implementation adapted from: + /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions + /// http://stackoverflow.com/a/536278 + /// + internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + { + VerifyIsAvx2Compatible(nameof(BulkConvertByteToNormalizedFloat)); + VerifySpanInput(source, dest, 8); + + var bVec = new Vector(256.0f / 255.0f); + var magicFloat = new Vector(32768.0f); + var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f + var mask = new Vector(255); + + ref Octet.OfByte sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref Octet.OfUInt32 destBaseAsWideOctet = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + + ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWideOctet); + + int n = dest.Length / 8; + + for (int i = 0; i < n; i++) + { + ref Octet.OfByte s = ref Unsafe.Add(ref sourceBase, i); + ref Octet.OfUInt32 d = ref Unsafe.Add(ref destBaseAsWideOctet, i); + d.LoadFrom(ref s); + } + + for (int i = 0; i < n; i++) + { + ref Vector df = ref Unsafe.Add(ref destBaseAsFloat, i); + + var vi = Vector.AsVectorUInt32(df); + vi &= mask; + vi |= magicInt; + + var vf = Vector.AsVectorSingle(vi); + vf = (vf - magicFloat) * bVec; + + df = vf; + } + } + + /// + /// Implementation of which is faster on older runtimes. + /// + internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) + { + VerifyIsAvx2Compatible(nameof(BulkConvertNormalizedFloatToByteClampOverflows)); + VerifySpanInput(source, dest, 8); + + if (source.Length == 0) + { + return; + } + + ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + int n = source.Length / 8; + + Vector magick = new Vector(32768.0f); + Vector scale = new Vector(255f) / new Vector(256f); + + // need to copy to a temporary struct, because + // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) + // does not work. TODO: This might be a CoreClr bug, need to ask/report + var temp = default(Octet.OfUInt32); + ref Vector tempRef = ref Unsafe.As>(ref temp); + + for (int i = 0; i < n; i++) + { + // union { float f; uint32_t i; } u; + // u.f = 32768.0f + x * (255.0f / 256.0f); + // return (uint8_t)u.i; + Vector x = Unsafe.Add(ref srcBase, i); + x = Vector.Max(x, Vector.Zero); + x = Vector.Min(x, Vector.One); + + x = (x * scale) + magick; + tempRef = x; + + ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); + d.LoadFrom(ref temp); + } + } + + /// + /// Convert all values normalized into [0..1] from 'source' + /// into 'dest' buffer of . The values are scaled up into [0-255] and rounded. + /// This implementation is SIMD optimized and works only when span Length is divisible by 8. + /// Based on: + /// + /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions + /// + /// + internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan source, Span dest) + { + VerifyIsAvx2Compatible(nameof(BulkConvertNormalizedFloatToByte)); + VerifySpanInput(source, dest, 8); + + if (source.Length == 0) + { + return; + } + + ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + int n = source.Length / 8; + + Vector magick = new Vector(32768.0f); + Vector scale = new Vector(255f) / new Vector(256f); + + // need to copy to a temporary struct, because + // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) + // does not work. TODO: This might be a CoreClr bug, need to ask/report + var temp = default(Octet.OfUInt32); + ref Vector tempRef = ref Unsafe.As>(ref temp); + + for (int i = 0; i < n; i++) + { + // union { float f; uint32_t i; } u; + // u.f = 32768.0f + x * (255.0f / 256.0f); + // return (uint8_t)u.i; + Vector x = Unsafe.Add(ref srcBase, i); + x = (x * scale) + magick; + tempRef = x; + + ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); + d.LoadFrom(ref temp); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs new file mode 100644 index 0000000000..e0d6187dca --- /dev/null +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -0,0 +1,178 @@ +using System; +using System.Diagnostics; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// ReSharper disable MemberHidesStaticFromOuterClass +namespace SixLabors.ImageSharp +{ + internal static partial class SimdUtils + { + /// + /// Implementation methods based on newer API-s (Vector.Widen, Vector.Narrow, Vector.ConvertTo*). + /// Only accelerated only on RyuJIT having dotnet/coreclr#10662 merged (.NET Core 2.1+ .NET 4.7.2+) + /// See: + /// https://github.com/dotnet/coreclr/pull/10662 + /// API Proposal: + /// https://github.com/dotnet/corefx/issues/15957 + /// + public static class ExtendedIntrinsics + { + public static bool IsAvailable { get; } = +#if NETCOREAPP2_1 + // TODO: Also available in .NET 4.7.2, we need to add a build target! + Vector.IsHardwareAccelerated; +#else + false; +#endif + + /// + /// as many elements as possible, slicing them down (keeping the remainder). + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertByteToNormalizedFloatReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + + if (!IsAvailable) + { + return; + } + + int remainder = ImageMaths.ModuloP2(source.Length, Vector.Count); + int adjustedCount = source.Length - remainder; + + if (adjustedCount > 0) + { + BulkConvertByteToNormalizedFloat(source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount)); + + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); + } + } + + /// + /// as many elements as possible, slicing them down (keeping the remainder). + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + + if (!IsAvailable) + { + return; + } + + int remainder = ImageMaths.ModuloP2(source.Length, Vector.Count); + int adjustedCount = source.Length - remainder; + + if (adjustedCount > 0) + { + BulkConvertNormalizedFloatToByteClampOverflows( + source.Slice(0, adjustedCount), + dest.Slice(0, adjustedCount)); + + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); + } + } + + /// + /// Implementation , which is faster on new RyuJIT runtime. + /// + internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + { + VerifySpanInput(source, dest, Vector.Count); + + int n = dest.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + Vector f0 = ConvertToSingle(w0); + Vector f1 = ConvertToSingle(w1); + Vector f2 = ConvertToSingle(w2); + Vector f3 = ConvertToSingle(w3); + + ref Vector d = ref Unsafe.Add(ref destBase, i * 4); + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; + } + } + + /// + /// Implementation of , which is faster on new .NET runtime. + /// + internal static void BulkConvertNormalizedFloatToByteClampOverflows( + ReadOnlySpan source, + Span dest) + { + VerifySpanInput(source, dest, Vector.Count); + + int n = dest.Length / Vector.Count; + + ref Vector sourceBase = + ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + + for (int i = 0; i < n; i++) + { + ref Vector s = ref Unsafe.Add(ref sourceBase, i * 4); + + Vector f0 = s; + Vector f1 = Unsafe.Add(ref s, 1); + Vector f2 = Unsafe.Add(ref s, 2); + Vector f3 = Unsafe.Add(ref s, 3); + + Vector w0 = ConvertToUInt32(f0); + Vector w1 = ConvertToUInt32(f1); + Vector w2 = ConvertToUInt32(f2); + Vector w3 = ConvertToUInt32(f3); + + Vector u0 = Vector.Narrow(w0, w1); + Vector u1 = Vector.Narrow(w2, w3); + + Vector b = Vector.Narrow(u0, u1); + + Unsafe.Add(ref destBase, i) = b; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector ConvertToUInt32(Vector vf) + { + Vector maxBytes = new Vector(255f); + vf *= maxBytes; + vf += new Vector(0.5f); + vf = Vector.Min(Vector.Max(vf, Vector.Zero), maxBytes); + Vector vi = Vector.ConvertToInt32(vf); + return Vector.AsVectorUInt32(vi); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector ConvertToSingle(Vector u) + { + Vector vi = Vector.AsVectorInt32(u); + Vector v = Vector.ConvertToSingle(vi); + v *= new Vector(1f / 255f); + return v; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs new file mode 100644 index 0000000000..565ea08f5d --- /dev/null +++ b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs @@ -0,0 +1,151 @@ +// 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; + +// ReSharper disable MemberHidesStaticFromOuterClass +namespace SixLabors.ImageSharp +{ + internal static partial class SimdUtils + { + /// + /// Fallback implementation based on (128bit). + /// For , efficient software fallback implementations are present, + /// and we hope that even mono's JIT is able to emit SIMD instructions for that type :P + /// + public static class FallbackIntrinsics128 + { + /// + /// as many elements as possible, slicing them down (keeping the remainder). + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertByteToNormalizedFloatReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + + int remainder = ImageMaths.Modulo4(source.Length); + int adjustedCount = source.Length - remainder; + + if (adjustedCount > 0) + { + BulkConvertByteToNormalizedFloat( + source.Slice(0, adjustedCount), + dest.Slice(0, adjustedCount)); + + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); + } + } + + /// + /// as many elements as possible, slicing them down (keeping the remainder). + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + + int remainder = ImageMaths.Modulo4(source.Length); + int adjustedCount = source.Length - remainder; + + if (adjustedCount > 0) + { + BulkConvertNormalizedFloatToByteClampOverflows( + source.Slice(0, adjustedCount), + dest.Slice(0, adjustedCount)); + + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); + } + } + + /// + /// Implementation of using . + /// + [MethodImpl(InliningOptions.ColdPath)] + internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + { + VerifySpanInput(source, dest, 4); + + int count = dest.Length / 4; + if (count == 0) + { + return; + } + + ref ByteVector4 sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref Vector4 dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + + const float Scale = 1f / 255f; + Vector4 d = default; + + for (int i = 0; i < count; i++) + { + ref ByteVector4 s = ref Unsafe.Add(ref sBase, i); + d.X = s.X; + d.Y = s.Y; + d.Z = s.Z; + d.W = s.W; + d *= Scale; + Unsafe.Add(ref dBase, i) = d; + } + } + + /// + /// Implementation of using . + /// + [MethodImpl(InliningOptions.ColdPath)] + internal static void BulkConvertNormalizedFloatToByteClampOverflows( + ReadOnlySpan source, + Span dest) + { + VerifySpanInput(source, dest, 4); + + int count = source.Length / 4; + if (count == 0) + { + return; + } + + ref Vector4 sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref ByteVector4 dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + + var half = new Vector4(0.5f); + var maxBytes = new Vector4(255f); + + for (int i = 0; i < count; i++) + { + Vector4 s = Unsafe.Add(ref sBase, i); + s *= maxBytes; + s += half; + + // I'm not sure if Vector4.Clamp() is properly implemented with intrinsics. + s = Vector4.Max(Vector4.Zero, s); + s = Vector4.Min(maxBytes, s); + + ref ByteVector4 d = ref Unsafe.Add(ref dBase, i); + d.X = (byte)s.X; + d.Y = (byte)s.Y; + d.Z = (byte)s.Z; + d.W = (byte)s.W; + } + } + + [StructLayout(LayoutKind.Sequential)] + private struct ByteVector4 + { + public byte X; + public byte Y; + public byte Z; + public byte W; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs new file mode 100644 index 0000000000..737e620061 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -0,0 +1,185 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Diagnostics; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tuples; + +namespace SixLabors.ImageSharp +{ + /// + /// Various extension and utility methods for and utilizing SIMD capabilities + /// + internal static partial class SimdUtils + { + /// + /// Gets a value indicating whether the code is being executed on AVX2 CPU where both float and integer registers are of size 256 byte. + /// + public static bool IsAvx2CompatibleArchitecture { get; } = + Vector.IsHardwareAccelerated && Vector.Count == 8 && Vector.Count == 8; + + /// + /// Transform all scalars in 'v' in a way that converting them to would have rounding semantics. + /// + /// The vector + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector4 PseudoRound(this Vector4 v) + { + var sign = Vector4.Clamp(v, new Vector4(-1), new Vector4(1)); + + return v + (sign * 0.5f); + } + + /// + /// Rounds all values in 'v' to the nearest integer following semantics. + /// Source: + /// + /// https://github.com/g-truc/glm/blob/master/glm/simd/common.h#L110 + /// + /// + /// The vector + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector FastRound(this Vector v) + { + Vector magic0 = new Vector(int.MinValue); // 0x80000000 + Vector sgn0 = Vector.AsVectorSingle(magic0); + Vector and0 = Vector.BitwiseAnd(sgn0, v); + Vector or0 = Vector.BitwiseOr(and0, new Vector(8388608.0f)); + Vector add0 = Vector.Add(v, or0); + Vector sub0 = Vector.Subtract(add0, or0); + return sub0; + } + + /// + /// Converts all input -s to -s normalized into [0..1]. + /// should be the of the same size as , + /// but there are no restrictions on the span's length. + /// + /// The source span of bytes + /// The destination span of floats + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + +#if NETCOREAPP2_1 + ExtendedIntrinsics.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); +#else + BasicIntrinsics256.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); +#endif + FallbackIntrinsics128.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); + + // Deal with the remainder: + if (source.Length > 0) + { + ConverByteToNormalizedFloatRemainder(source, dest); + } + } + + /// + /// Convert all values normalized into [0..1] from 'source' into 'dest' buffer of . + /// The values are scaled up into [0-255] and rounded, overflows are clamped. + /// should be the of the same size as , + /// but there are no restrictions on the span's length. + /// + /// The source span of floats + /// The destination span of bytes + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + +#if NETCOREAPP2_1 + ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); +#else + BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); +#endif + FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); + + // Deal with the remainder: + if (source.Length > 0) + { + ConvertNormalizedFloatToByteRemainder(source, dest); + } + } + + [MethodImpl(InliningOptions.ColdPath)] + private static void ConverByteToNormalizedFloatRemainder(ReadOnlySpan source, Span dest) + { + ref byte sBase = ref MemoryMarshal.GetReference(source); + ref float dBase = ref MemoryMarshal.GetReference(dest); + + // There are at most 3 elements at this point, having a for loop is overkill. + // Let's minimize the no. of instructions! + switch (source.Length) + { + case 3: + Unsafe.Add(ref dBase, 2) = Unsafe.Add(ref sBase, 2) / 255f; + goto case 2; + case 2: + Unsafe.Add(ref dBase, 1) = Unsafe.Add(ref sBase, 1) / 255f; + goto case 1; + case 1: + dBase = sBase / 255f; + break; + } + } + + [MethodImpl(InliningOptions.ColdPath)] + private static void ConvertNormalizedFloatToByteRemainder(ReadOnlySpan source, Span dest) + { + ref float sBase = ref MemoryMarshal.GetReference(source); + ref byte dBase = ref MemoryMarshal.GetReference(dest); + + switch (source.Length) + { + case 3: + Unsafe.Add(ref dBase, 2) = ConvertToByte(Unsafe.Add(ref sBase, 2)); + goto case 2; + case 2: + Unsafe.Add(ref dBase, 1) = ConvertToByte(Unsafe.Add(ref sBase, 1)); + goto case 1; + case 1: + dBase = ConvertToByte(sBase); + break; + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + private static byte ConvertToByte(float f) => (byte)ComparableExtensions.Clamp((f * 255f) + 0.5f, 0, 255f); + + [Conditional("DEBUG")] + private static void VerifyIsAvx2Compatible(string operation) + { + if (!IsAvx2CompatibleArchitecture) + { + throw new NotSupportedException($"{operation} is supported only on AVX2 CPU!"); + } + } + + [Conditional("DEBUG")] + private static void VerifySpanInput(ReadOnlySpan source, Span dest, int shouldBeDivisibleBy) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + DebugGuard.IsTrue( + ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0, + nameof(source), + $"length should be divisable by {shouldBeDivisibleBy}!"); + } + + [Conditional("DEBUG")] + private static void VerifySpanInput(ReadOnlySpan source, Span dest, int shouldBeDivisibleBy) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + DebugGuard.IsTrue( + ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0, + nameof(source), + $"length should be divisable by {shouldBeDivisibleBy}!"); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Tuples/Octet.cs b/src/ImageSharp/Common/Tuples/Octet.cs new file mode 100644 index 0000000000..539b74e324 --- /dev/null +++ b/src/ImageSharp/Common/Tuples/Octet.cs @@ -0,0 +1,109 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.Tuples +{ + /// + /// Contains 8 element value tuples of various types. + /// + internal static class Octet + { + /// + /// Value tuple of -s + /// + [StructLayout(LayoutKind.Explicit, Size = 8 * sizeof(uint))] + public struct OfUInt32 + { + [FieldOffset(0 * sizeof(uint))] + public uint V0; + + [FieldOffset(1 * sizeof(uint))] + public uint V1; + + [FieldOffset(2 * sizeof(uint))] + public uint V2; + + [FieldOffset(3 * sizeof(uint))] + public uint V3; + + [FieldOffset(4 * sizeof(uint))] + public uint V4; + + [FieldOffset(5 * sizeof(uint))] + public uint V5; + + [FieldOffset(6 * sizeof(uint))] + public uint V6; + + [FieldOffset(7 * sizeof(uint))] + public uint V7; + + public override string ToString() + { + return $"{nameof(Octet)}.{nameof(OfUInt32)}({this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7})"; + } + + [MethodImpl(InliningOptions.ShortMethod)] + public void LoadFrom(ref OfByte src) + { + this.V0 = src.V0; + this.V1 = src.V1; + this.V2 = src.V2; + this.V3 = src.V3; + this.V4 = src.V4; + this.V5 = src.V5; + this.V6 = src.V6; + this.V7 = src.V7; + } + } + + /// + /// Value tuple of -s + /// + [StructLayout(LayoutKind.Explicit, Size = 8)] + public struct OfByte + { + [FieldOffset(0)] + public byte V0; + + [FieldOffset(1)] + public byte V1; + + [FieldOffset(2)] + public byte V2; + + [FieldOffset(3)] + public byte V3; + + [FieldOffset(4)] + public byte V4; + + [FieldOffset(5)] + public byte V5; + + [FieldOffset(6)] + public byte V6; + + [FieldOffset(7)] + public byte V7; + + public override string ToString() + { + return $"{nameof(Octet)}.{nameof(OfByte)}({this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7})"; + } + + [MethodImpl(InliningOptions.ShortMethod)] + public void LoadFrom(ref OfUInt32 src) + { + this.V0 = (byte)src.V0; + this.V1 = (byte)src.V1; + this.V2 = (byte)src.V2; + this.V3 = (byte)src.V3; + this.V4 = (byte)src.V4; + this.V5 = (byte)src.V5; + this.V6 = (byte)src.V6; + this.V7 = (byte)src.V7; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Tuples/Vector4Pair.cs b/src/ImageSharp/Common/Tuples/Vector4Pair.cs index 309d5e2e56..cae283d628 100644 --- a/src/ImageSharp/Common/Tuples/Vector4Pair.cs +++ b/src/ImageSharp/Common/Tuples/Vector4Pair.cs @@ -2,11 +2,12 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.Common.Tuples +namespace SixLabors.ImageSharp.Tuples { /// /// Its faster to process multiple Vector4-s together, so let's pair them! /// On AVX2 this pair should be convertible to of ! + /// TODO: Investigate defining this as union with an Octet.OfSingle type. /// [StructLayout(LayoutKind.Sequential)] internal struct Vector4Pair @@ -15,8 +16,6 @@ namespace SixLabors.ImageSharp.Common.Tuples public Vector4 B; - private static readonly Vector4 Scale = new Vector4(1 / 255f); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public void MultiplyInplace(float value) { @@ -52,8 +51,9 @@ namespace SixLabors.ImageSharp.Common.Tuples b = b.FastRound(); // Downscale by 1/255 - this.A *= Scale; - this.B *= Scale; + var scale = new Vector4(1 / 255f); + this.A *= scale; + this.B *= scale; } /// @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Common.Tuples public override string ToString() { - return $"{this.A}, {this.B}"; + return $"{nameof(Vector4Pair)}({this.A}, {this.B})"; } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 71852acddd..dabab651d0 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -219,8 +219,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp where TPixel : struct, IPixel { TPixel color = default; - var rgba = new Rgba32(0, 0, 0, 255); - using (Buffer2D buffer = this.memoryAllocator.Allocate2D(width, height, AllocationOptions.Clean)) { this.UncompressRle8(width, buffer.GetSpan()); @@ -233,8 +231,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp for (int x = 0; x < width; x++) { - rgba.Bgr = Unsafe.As(ref colors[bufferRow[x] * 4]); - color.PackFromRgba32(rgba); + color.PackFromBgr24(Unsafe.As(ref colors[bufferRow[x] * 4])); pixelRow[x] = color; } } @@ -352,8 +349,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp using (IManagedByteBuffer row = this.memoryAllocator.AllocateManagedByteBuffer(arrayWidth + padding, AllocationOptions.Clean)) { TPixel color = default; - var rgba = new Rgba32(0, 0, 0, 255); - Span rowSpan = row.GetSpan(); for (int y = 0; y < height; y++) @@ -363,7 +358,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp int offset = 0; Span pixelRow = pixels.GetRowSpan(newY); - // TODO: Could use PixelOperations here! for (int x = 0; x < arrayWidth; x++) { int colOffset = x * ppb; @@ -371,9 +365,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { int colorIndex = ((rowSpan[offset] >> (8 - bits - (shift * bits))) & mask) * 4; - // Stored in b-> g-> r order. - rgba.Bgr = Unsafe.As(ref colors[colorIndex]); - color.PackFromRgba32(rgba); + color.PackFromBgr24(Unsafe.As(ref colors[colorIndex])); pixelRow[newX] = color; } @@ -397,7 +389,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp int padding = CalculatePadding(width, 2); int stride = (width * 2) + padding; TPixel color = default; - var rgba = new Rgba32(0, 0, 0, 255); using (IManagedByteBuffer buffer = this.memoryAllocator.AllocateManagedByteBuffer(stride)) { @@ -412,11 +403,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp { short temp = BitConverter.ToInt16(buffer.Array, offset); - rgba.R = GetBytesFrom5BitValue((temp & Rgb16RMask) >> 10); - rgba.G = GetBytesFrom5BitValue((temp & Rgb16GMask) >> 5); - rgba.B = GetBytesFrom5BitValue(temp & Rgb16BMask); + var rgb = new Rgb24( + GetBytesFrom5BitValue((temp & Rgb16RMask) >> 10), + GetBytesFrom5BitValue((temp & Rgb16GMask) >> 5), + GetBytesFrom5BitValue(temp & Rgb16BMask)); - color.PackFromRgba32(rgba); + color.PackFromRgb24(rgb); pixelRow[x] = color; offset += 2; } @@ -537,7 +529,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.metaData = meta; short bitsPerPixel = this.infoHeader.BitsPerPixel; - var bmpMetaData = this.metaData.GetFormatMetaData(BmpFormat.Instance); + BmpMetaData bmpMetaData = this.metaData.GetFormatMetaData(BmpFormat.Instance); // We can only encode at these bit rates so far. if (bitsPerPixel.Equals((short)BmpBitsPerPixel.Pixel24) diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 44e42528cf..186ff812f7 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -101,9 +101,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp var fileHeader = new BmpFileHeader( type: 19778, // BM - offset: 54, + fileSize: 54 + infoHeader.ImageSize, reserved: 0, - fileSize: 54 + infoHeader.ImageSize); + offset: 54); #if NETCOREAPP2_1 Span buffer = stackalloc byte[40]; diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 207f126f9e..155e6484f7 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -481,22 +481,36 @@ namespace SixLabors.ImageSharp.Formats.Gif } ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.GetPixelRowSpan(writeY)); - var rgba = new Rgba32(0, 0, 0, 255); + bool transFlag = this.graphicsControlExtension.TransparencyFlag; - // #403 The left + width value can be larger than the image width - for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++) + if (!transFlag) { - int index = Unsafe.Add(ref indicesRef, i); - - if (!this.graphicsControlExtension.TransparencyFlag - || this.graphicsControlExtension.TransparencyIndex != index) + // #403 The left + width value can be larger than the image width + for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++) { + int index = Unsafe.Add(ref indicesRef, i); ref TPixel pixel = ref Unsafe.Add(ref rowRef, x); - rgba.Rgb = colorTable[index]; - pixel.PackFromRgba32(rgba); + Rgb24 rgb = colorTable[index]; + pixel.PackFromRgb24(rgb); + + i++; } + } + else + { + byte transIndex = this.graphicsControlExtension.TransparencyIndex; + for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++) + { + int index = Unsafe.Add(ref indicesRef, i); + if (transIndex != index) + { + ref TPixel pixel = ref Unsafe.Add(ref rowRef, x); + Rgb24 rgb = colorTable[index]; + pixel.PackFromRgb24(rgb); + } - i++; + i++; + } } } diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index a8cd169e5d..7851b82ee3 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -209,16 +210,20 @@ namespace SixLabors.ImageSharp.Formats.Gif { // Transparent pixels are much more likely to be found at the end of a palette int index = -1; - Rgba32 trans = default; + int length = quantized.Palette.Length; - ref TPixel paletteRef = ref MemoryMarshal.GetReference(quantized.Palette.AsSpan()); - for (int i = quantized.Palette.Length - 1; i >= 0; i--) + using (IMemoryOwner rgbaBuffer = this.memoryAllocator.Allocate(length)) { - ref TPixel entry = ref Unsafe.Add(ref paletteRef, i); - entry.ToRgba32(ref trans); - if (trans.Equals(default)) + Span rgbaSpan = rgbaBuffer.GetSpan(); + ref Rgba32 paletteRef = ref MemoryMarshal.GetReference(rgbaSpan); + PixelOperations.Instance.ToRgba32(quantized.Palette, rgbaSpan, length); + + for (int i = quantized.Palette.Length - 1; i >= 0; i--) { - index = i; + if (Unsafe.Add(ref paletteRef, i).Equals(default)) + { + index = i; + } } } @@ -405,24 +410,13 @@ namespace SixLabors.ImageSharp.Formats.Gif private void WriteColorTable(QuantizedFrame image, Stream stream) where TPixel : struct, IPixel { - int pixelCount = image.Palette.Length; - // The maximium number of colors for the bit depth int colorTableLength = ImageMaths.GetColorCountForBitDepth(this.bitDepth) * 3; - Rgb24 rgb = default; + int pixelCount = image.Palette.Length; using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) { - ref TPixel paletteRef = ref MemoryMarshal.GetReference(image.Palette.AsSpan()); - ref Rgb24 rgb24Ref = ref Unsafe.As(ref MemoryMarshal.GetReference(colorTable.GetSpan())); - for (int i = 0; i < pixelCount; i++) - { - ref TPixel entry = ref Unsafe.Add(ref paletteRef, i); - entry.ToRgb24(ref rgb); - Unsafe.Add(ref rgb24Ref, i) = rgb; - } - - // Write the palette to the stream + PixelOperations.Instance.ToRgb24Bytes(image.Palette.AsSpan(), colorTable.GetSpan(), pixelCount); stream.Write(colorTable.Array, 0, colorTableLength); } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs index 4b2626c582..1dc72aaf5b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs @@ -6,7 +6,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Common.Tuples; +using SixLabors.ImageSharp.Tuples; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { @@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order: ref Vector4Octet destination = ref Unsafe.Add(ref resultBase, i); - destination.Collect(ref r, ref g, ref b); + destination.Pack(ref r, ref g, ref b); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs index ab4947e65c..46644258b1 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs @@ -6,7 +6,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Common.Tuples; +using SixLabors.ImageSharp.Tuples; // ReSharper disable ImpureMethodCallOnReadonlyValueField namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters @@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order: ref Vector4Octet destination = ref Unsafe.Add(ref resultBase, i); - destination.Collect(ref rr, ref gg, ref bb); + destination.Pack(ref rr, ref gg, ref bb); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs index 60abb7fb2c..456636dc39 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs @@ -6,8 +6,8 @@ using System.Collections.Generic; using System.Linq; using System.Numerics; -using SixLabors.ImageSharp.Common.Tuples; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.Tuples; using SixLabors.Memory; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters @@ -157,9 +157,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters public Vector4 V0, V1, V2, V3, V4, V5, V6, V7; /// - /// Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order. + /// Pack (r0,r1...r7) (g0,g1...g7) (b0,b1...b7) vector values as (r0,g0,b0,1), (r1,g1,b1,1) ... /// - public void Collect(ref Vector4Pair r, ref Vector4Pair g, ref Vector4Pair b) + public void Pack(ref Vector4Pair r, ref Vector4Pair g, ref Vector4Pair b) { this.V0.X = r.A.X; this.V0.Y = g.A.X; diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index a46d83707e..1e9dbc71a1 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Buffers.Binary; using System.Collections.Generic; using System.IO; @@ -312,11 +313,6 @@ namespace SixLabors.ImageSharp.Formats.Png private void CollectGrayscaleBytes(ReadOnlySpan rowSpan) where TPixel : struct, IPixel { - // Use ITU-R recommendation 709 to match libpng. - const float RX = .2126F; - const float GX = .7152F; - const float BX = .0722F; - ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); Span rawScanlineSpan = this.rawScanline.GetSpan(); ref byte rawScanlineSpanRef = ref MemoryMarshal.GetReference(rawScanlineSpan); @@ -327,12 +323,18 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.use16Bit) { // 16 bit grayscale - Rgb48 rgb = default; - for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2) + using (IMemoryOwner luminanceBuffer = this.memoryAllocator.Allocate(rowSpan.Length)) { - Unsafe.Add(ref rowSpanRef, x).ToRgb48(ref rgb); - ushort luminance = (ushort)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance); + Span luminanceSpan = luminanceBuffer.GetSpan(); + ref Gray16 luminanceRef = ref MemoryMarshal.GetReference(luminanceSpan); + PixelOperations.Instance.ToGray16(rowSpan, luminanceSpan, rowSpan.Length); + + // Can't map directly to byte array as it's big endian. + for (int x = 0, o = 0; x < luminanceSpan.Length; x++, o += 2) + { + Gray16 luminance = Unsafe.Add(ref luminanceRef, x); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance.PackedValue); + } } } else @@ -340,12 +342,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.bitDepth == 8) { // 8 bit grayscale - Rgb24 rgb = default; - for (int x = 0; x < rowSpan.Length; x++) - { - Unsafe.Add(ref rowSpanRef, x).ToRgb24(ref rgb); - Unsafe.Add(ref rawScanlineSpanRef, x) = (byte)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)); - } + PixelOperations.Instance.ToGray8Bytes(rowSpan, rawScanlineSpan, rowSpan.Length); } else { @@ -356,14 +353,9 @@ namespace SixLabors.ImageSharp.Formats.Png Span tempSpan = temp.GetSpan(); ref byte tempSpanRef = ref MemoryMarshal.GetReference(tempSpan); - Rgb24 rgb = default; - for (int x = 0; x < rowSpan.Length; x++) - { - Unsafe.Add(ref rowSpanRef, x).ToRgb24(ref rgb); - float luminance = ((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)) / scaleFactor; - Unsafe.Add(ref tempSpanRef, x) = (byte)luminance; - this.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth); - } + // We need to first create an array of luminance bytes then scale them down to the correct bit depth. + PixelOperations.Instance.ToGray8Bytes(rowSpan, tempSpan, rowSpan.Length); + this.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth, scaleFactor); } } } @@ -373,23 +365,31 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.use16Bit) { // 16 bit grayscale + alpha - Rgba64 rgba = default; - for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 4) + // TODO: Should we consider in the future a GrayAlpha32 type. + using (IMemoryOwner rgbaBuffer = this.memoryAllocator.Allocate(rowSpan.Length)) { - Unsafe.Add(ref rowSpanRef, x).ToRgba64(ref rgba); - ushort luminance = (ushort)((RX * rgba.R) + (GX * rgba.G) + (BX * rgba.B)); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.A); + Span rgbaSpan = rgbaBuffer.GetSpan(); + ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan); + PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan, rowSpan.Length); + + // Can't map directly to byte array as it's big endian. + for (int x = 0, o = 0; x < rgbaSpan.Length; x++, o += 4) + { + Rgba64 rgba = Unsafe.Add(ref rgbaRef, x); + ushort luminance = ImageMaths.Get16BitBT709Luminance(rgba.R, rgba.G, rgba.B); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.A); + } } } else { // 8 bit grayscale + alpha - Rgba32 rgba = default; + // TODO: Should we consider in the future a GrayAlpha16 type. for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2) { - Unsafe.Add(ref rowSpanRef, x).ToRgba32(ref rgba); - Unsafe.Add(ref rawScanlineSpanRef, o) = (byte)((RX * rgba.R) + (GX * rgba.G) + (BX * rgba.B)); + var rgba = Unsafe.Add(ref rowSpanRef, x).ToRgba32(); + Unsafe.Add(ref rawScanlineSpanRef, o) = ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); Unsafe.Add(ref rawScanlineSpanRef, o + 1) = rgba.A; } } @@ -425,15 +425,21 @@ namespace SixLabors.ImageSharp.Formats.Png case 8: { // 16 bit Rgba - Rgba64 rgba = default; - ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); - for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8) + using (IMemoryOwner rgbaBuffer = this.memoryAllocator.Allocate(rowSpan.Length)) { - Unsafe.Add(ref rowSpanRef, x).ToRgba64(ref rgba); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgba.R); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.G); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgba.B); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 6, 2), rgba.A); + Span rgbaSpan = rgbaBuffer.GetSpan(); + ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan); + PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan, rowSpan.Length); + + // Can't map directly to byte array as it's big endian. + for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8) + { + Rgba64 rgba = Unsafe.Add(ref rgbaRef, x); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgba.R); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.G); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgba.B); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 6, 2), rgba.A); + } } break; @@ -442,14 +448,20 @@ namespace SixLabors.ImageSharp.Formats.Png default: { // 16 bit Rgb - Rgb48 rgb = default; - ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); - for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6) + using (IMemoryOwner rgbBuffer = this.memoryAllocator.Allocate(rowSpan.Length)) { - Unsafe.Add(ref rowSpanRef, x).ToRgb48(ref rgb); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgb.R); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgb.G); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgb.B); + Span rgbSpan = rgbBuffer.GetSpan(); + ref Rgb48 rgbRef = ref MemoryMarshal.GetReference(rgbSpan); + PixelOperations.Instance.ToRgb48(rowSpan, rgbSpan, rowSpan.Length); + + // Can't map directly to byte array as it's big endian. + for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6) + { + Rgb48 rgb = Unsafe.Add(ref rgbRef, x); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgb.R); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgb.G); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgb.B); + } } break; @@ -624,7 +636,6 @@ namespace SixLabors.ImageSharp.Formats.Png TPixel[] palette = quantized.Palette; int paletteLength = Math.Min(palette.Length, 256); int colorTableLength = paletteLength * 3; - Rgba32 rgba = default; bool anyAlpha = false; using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) @@ -639,7 +650,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (quantizedSpan.IndexOf((byte)i) > -1) { int offset = i * 3; - palette[i].ToRgba32(ref rgba); + var rgba = palette[i].ToRgba32(); byte alpha = rgba.A; @@ -851,7 +862,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// The source span in 8 bits. /// The resultant span in . /// The bit depth. - private void ScaleDownFrom8BitArray(ReadOnlySpan source, Span result, int bits) + /// The scaling factor. + private void ScaleDownFrom8BitArray(ReadOnlySpan source, Span result, int bits, float scale = 1) { ref byte sourceRef = ref MemoryMarshal.GetReference(source); ref byte resultRef = ref MemoryMarshal.GetReference(result); @@ -864,7 +876,7 @@ namespace SixLabors.ImageSharp.Formats.Png for (int i = 0; i < source.Length; i++) { - int value = Unsafe.Add(ref sourceRef, i) & mask; + int value = ((int)MathF.Round(Unsafe.Add(ref sourceRef, i) / scale)) & mask; v |= value << shift; if (shift == 0) diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index 5ea25e72d4..70f2cb04b6 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -32,30 +32,19 @@ namespace SixLabors.ImageSharp.Formats.Png { if (header.BitDepth == 16) { - Rgb48 rgb48 = default; for (int x = 0, o = 0; x < header.Width; x++, o += 2) { ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - rgb48.R = luminance; - rgb48.G = luminance; - rgb48.B = luminance; - - pixel.PackFromRgb48(rgb48); + pixel.PackFromGray16(new Gray16(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } else { - // TODO: We should really be using Rgb24 here but IPixel does not have a PackFromRgb24 method. - var rgba32 = new Rgba32(0, 0, 0, byte.MaxValue); for (int x = 0; x < header.Width; x++) { byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * scaleFactor); - rgba32.R = luminance; - rgba32.G = luminance; - rgba32.B = luminance; - - pixel.PackFromRgba32(rgba32); + pixel.PackFromGray8(new Gray8(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -116,30 +105,19 @@ namespace SixLabors.ImageSharp.Formats.Png { if (header.BitDepth == 16) { - Rgb48 rgb48 = default; for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += 2) { ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - rgb48.R = luminance; - rgb48.G = luminance; - rgb48.B = luminance; - - pixel.PackFromRgb48(rgb48); + pixel.PackFromGray16(new Gray16(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } else { - // TODO: We should really be using Rgb24 here but IPixel does not have a PackFromRgb24 method. - var rgba32 = new Rgba32(0, 0, 0, byte.MaxValue); for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++) { byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor); - rgba32.R = luminance; - rgba32.G = luminance; - rgba32.B = luminance; - - pixel.PackFromRgba32(rgba32); + pixel.PackFromGray8(new Gray8(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -311,14 +289,12 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - // TODO: We should have PackFromRgb24. - var rgba = new Rgba32(0, 0, 0, byte.MaxValue); for (int x = 0; x < header.Width; x++) { int index = Unsafe.Add(ref scanlineSpanRef, x); - rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); + Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index); - pixel.PackFromRgba32(rgba); + pixel.PackFromRgb24(rgb); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -358,13 +334,12 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - var rgba = new Rgba32(0, 0, 0, byte.MaxValue); for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++) { int index = Unsafe.Add(ref scanlineSpanRef, o); - rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); + Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index); - pixel.PackFromRgba32(rgba); + pixel.PackFromRgb24(rgb); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -511,14 +486,14 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - var rgba = new Rgba32(0, 0, 0, byte.MaxValue); + Rgb24 rgb = default; for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += bytesPerPixel) { - rgba.R = Unsafe.Add(ref scanlineSpanRef, o); - rgba.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample); - rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); + rgb.R = Unsafe.Add(ref scanlineSpanRef, o); + rgb.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample); + rgb.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); - pixel.PackFromRgba32(rgba); + pixel.PackFromRgb24(rgb); Unsafe.Add(ref rowSpanRef, x) = pixel; } } diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index be1792ced1..ecf9e13ceb 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -2,8 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Buffers; -using System.Numerics; using System.Runtime.CompilerServices; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; @@ -289,22 +287,16 @@ namespace SixLabors.ImageSharp var target = new ImageFrame(configuration, this.Width, this.Height, this.MetaData.DeepClone()); - ParallelHelper.IterateRowsWithTempBuffer( + ParallelHelper.IterateRows( this.Bounds(), configuration, - (rows, tempRowBuffer) => + (rows) => { for (int y = rows.Min; y < rows.Max; y++) { Span sourceRow = this.GetPixelRowSpan(y); Span targetRow = target.GetPixelRowSpan(y); - Span tempRowSpan = tempRowBuffer.Span; - - PixelOperations.Instance.ToScaledVector4(sourceRow, tempRowSpan, sourceRow.Length); - PixelOperations.Instance.PackFromScaledVector4( - tempRowSpan, - targetRow, - targetRow.Length); + PixelOperations.Instance.To(sourceRow, targetRow, sourceRow.Length); } }); diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 83b2b12604..17e417dca8 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -76,10 +76,42 @@ TextTemplatingFileGenerator PixelOperations{TPixel}.Generated.cs + + TextTemplatingFileGenerator + Argb32.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Bgr24.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Bgra32.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Gray8.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Gray16.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Rgb24.PixelOperations.Generated.cs + TextTemplatingFileGenerator Rgba32.PixelOperations.Generated.cs + + TextTemplatingFileGenerator + Rgb48.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Rgba64.PixelOperations.Generated.cs + PorterDuffFunctions.Generated.cs TextTemplatingFileGenerator @@ -110,11 +142,51 @@ True PixelOperations{TPixel}.Generated.tt + + True + True + Argb32.PixelOperations.Generated.tt + + + True + True + Bgr24.PixelOperations.Generated.tt + + + True + True + Bgra32.PixelOperations.Generated.tt + + + True + True + Gray8.PixelOperations.Generated.tt + + + True + True + Gray16.PixelOperations.Generated.tt + + + True + True + Rgb24.PixelOperations.Generated.tt + True True Rgba32.PixelOperations.Generated.tt + + True + True + Rgb48.PixelOperations.Generated.tt + + + True + True + Rgba64.PixelOperations.Generated.tt + True True diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs index a8d97d31a2..1e724768d0 100644 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/Alpha8.cs @@ -18,11 +18,14 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Initializes a new instance of the struct. /// - /// The alpha component - public Alpha8(float alpha) - { - this.PackedValue = Pack(alpha); - } + /// The alpha component. + public Alpha8(byte alpha) => this.PackedValue = alpha; + + /// + /// Initializes a new instance of the struct. + /// + /// The alpha component. + public Alpha8(float alpha) => this.PackedValue = Pack(alpha); /// public byte PackedValue { get; set; } @@ -39,11 +42,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Alpha8 left, Alpha8 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Alpha8 left, Alpha8 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -53,161 +53,91 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Alpha8 left, Alpha8 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Alpha8 left, Alpha8 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(vector.W); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(0, 0, 0, this.PackedValue / 255F); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(0, 0, 0, this.PackedValue / 255F); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackedValue = source.A; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackedValue = source.A; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackedValue = source.A; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackedValue = byte.MaxValue; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackedValue = source.A; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackedValue = source.A; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest = default(Rgb24); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackedValue = byte.MaxValue; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = 0; - dest.G = 0; - dest.B = 0; - dest.A = this.PackedValue; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackedValue = byte.MaxValue; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - dest.R = 0; - dest.G = 0; - dest.B = 0; - dest.A = this.PackedValue; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackedValue = byte.MaxValue; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - dest = default(Bgr24); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackedValue = source.A; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - dest.R = 0; - dest.G = 0; - dest.B = 0; - dest.A = this.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(0, 0, 0, this.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackedValue = byte.MaxValue; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) - { - dest.R = 0; - dest.G = 0; - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// /// Compares an object with the packed vector. /// /// The object to compare. /// True if the object is equal to the packed vector. - public override bool Equals(object obj) - { - return obj is Alpha8 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Alpha8 other && this.Equals(other); /// /// Compares another Alpha8 packed vector with the packed vector. /// /// The Alpha8 packed vector to compare. /// True if the packed vectors are equal. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Alpha8 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Alpha8 other) => this.PackedValue.Equals(other.PackedValue); /// /// Gets a string representation of the packed vector. /// /// A string representation of the packed vector. - public override string ToString() - { - return (this.PackedValue / 255F).ToString(); - } + public override string ToString() => $"Alpha8({this.PackedValue})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); /// @@ -215,10 +145,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The float containing the value to pack. /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static byte Pack(float alpha) - { - return (byte)Math.Round(alpha.Clamp(0, 1) * 255F); - } + [MethodImpl(InliningOptions.ShortMethod)] + private static byte Pack(float alpha) => (byte)Math.Round(alpha.Clamp(0, 1F) * 255F); } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/Argb32.cs index 51d3964ef8..1e3bd93262 100644 --- a/src/ImageSharp/PixelFormats/Argb32.cs +++ b/src/ImageSharp/PixelFormats/Argb32.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// as it avoids the need to create new values for modification operations. /// [StructLayout(LayoutKind.Sequential)] - public struct Argb32 : IPixel, IPackedVector + public partial struct Argb32 : IPixel, IPackedVector { /// /// Gets or sets the alpha component. @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The red component. /// The green component. /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(byte r, byte g, byte b) { this.R = r; @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(byte r, byte g, byte b, byte a) { this.R = r; @@ -89,12 +89,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(float r, float g, float b, float a = 1) - : this() - { - this.Pack(r, g, b, a); - } + : this() => this.Pack(r, g, b, a); /// /// Initializes a new instance of the struct. @@ -102,12 +99,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed vector. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(Vector3 vector) - : this() - { - this.Pack(ref vector); - } + : this() => this.Pack(ref vector); /// /// Initializes a new instance of the struct. @@ -115,12 +109,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed vector. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(Vector4 vector) - : this() - { - this.Pack(ref vector); - } + : this() => this.Pack(ref vector); /// /// Initializes a new instance of the struct. @@ -128,22 +119,19 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The packed value. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(uint packed) - : this() - { - this.Argb = packed; - } + : this() => this.Argb = packed; /// /// Gets or sets the packed representation of the Argb32 struct. /// public uint Argb { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } @@ -157,20 +145,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Argb32 left, Argb32 right) - { - return left.Argb == right.Argb; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Argb32 left, Argb32 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -180,62 +161,44 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Argb32 left, Argb32 right) - { - return left.Argb != right.Argb; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Argb32 left, Argb32 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.Pack(ref vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackedValue = source.PackedValue; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) { this.R = source.R; this.G = source.G; this.B = source.B; - this.A = source.A; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackedValue = source.PackedValue; + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) { this.R = source.R; @@ -244,136 +207,88 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = source.A; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + this.A = byte.MaxValue; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; + this.A = byte.MaxValue; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) { - dest = this; + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = byte.MaxValue; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; - } - - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A); - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Bgra32 ToBgra32() => new Bgra32(this.R, this.G, this.B, this.A); - - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Argb32 ToArgb32() => this; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - this.A = (byte)(((source.A * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); + this.A = ImageMaths.DownScaleFrom16BitTo8Bit(source.A); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) - { - return obj is Argb32 argb32 && this.Equals(argb32); - } + public override bool Equals(object obj) => obj is Argb32 argb32 && this.Equals(argb32); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Argb32 other) - { - return this.Argb == other.Argb; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Argb32 other) => this.Argb == other.Argb; /// /// Gets a string representation of the packed vector. /// /// A string representation of the packed vector. - public override string ToString() - { - return $"({this.R},{this.G},{this.B},{this.A})"; - } + public override string ToString() => $"Argb({this.A}, {this.R}, {this.G}, {this.B})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.Argb.GetHashCode(); - /// - /// Gets the representation without normalizing to [0, 1] - /// - /// A of values in [0, 255] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Vector4 ToByteScaledVector4() - { - return new Vector4(this.R, this.G, this.B, this.A); - } - /// /// Packs the four floats into a color. /// @@ -381,7 +296,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The y-component /// The z-component /// The w-component - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(float x, float y, float z, float w) { var value = new Vector4(x, y, z, w); @@ -392,7 +307,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs a into a uint. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector3 vector) { var value = new Vector4(vector, 1); @@ -403,7 +318,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector4 vector) { vector *= MaxBytes; diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/Bgr24.cs index 1f401f1a13..ed65bebf7f 100644 --- a/src/ImageSharp/PixelFormats/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/Bgr24.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// [StructLayout(LayoutKind.Explicit)] - public struct Bgr24 : IPixel + public partial struct Bgr24 : IPixel { /// /// The blue component. @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The red component. /// The green component. /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Bgr24(byte r, byte g, byte b) { this.R = r; @@ -49,39 +49,54 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = b; } + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgr24 left, Bgr24 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgr24 left, Bgr24 right) => !left.Equals(right); + /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Bgr24 other) - { - return this.R == other.R && this.G == other.G && this.B == other.B; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - public override bool Equals(object obj) - { - return obj is Bgr24 other && this.Equals(other); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) { - int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); - return HashHelpers.Combine(hash, this.B.GetHashCode()); + Rgba32 rgba = default; + rgba.PackFromVector4(vector); + this.PackFromRgba32(rgba); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this = source.Bgr; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) { this.R = source.R; @@ -90,7 +105,11 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this = source; + + /// + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) { this.R = source.R; @@ -99,109 +118,75 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) { - return this.ToVector4(); + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) { - Rgba32 rgba = default; - rgba.PackFromVector4(vector); - this.PackFromRgba32(rgba); + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) { - return new Rgba32(this.R, this.G, this.B, 255).ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; + this.R = source.R; + this.G = source.G; + this.B = source.B; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this = source.Bgr; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, byte.MaxValue); /// - public void ToBgr24(ref Bgr24 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) { - dest = this; + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); } /// - public void ToBgra32(ref Bgra32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba64(Rgba64 source) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) - { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Bgr24 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + public override bool Equals(object obj) => obj is Bgr24 other && this.Equals(other); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) - { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - } + /// + public override string ToString() => $"Bgra({this.B}, {this.G}, {this.R})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override string ToString() + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() { - return $"({this.B},{this.G},{this.R})"; + int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); + return HashHelpers.Combine(hash, this.B.GetHashCode()); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/Bgr565.cs index 570b975dba..04af6ef0f1 100644 --- a/src/ImageSharp/PixelFormats/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/Bgr565.cs @@ -8,7 +8,8 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.PixelFormats { /// - /// Packed pixel type containing unsigned normalized values ranging from 0 to 1. The x and z components use 5 bits, and the y component uses 6 bits. + /// Packed pixel type containing unsigned normalized values ranging from 0 to 1. + /// The x and z components use 5 bits, and the y component uses 6 bits. /// /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. /// @@ -22,8 +23,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// The y-component /// The z-component public Bgr565(float x, float y, float z) + : this(new Vector3(x, y, z)) { - this.PackedValue = Pack(x, y, z); } /// @@ -32,10 +33,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed value. /// - public Bgr565(Vector3 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z); - } + public Bgr565(Vector3 vector) => this.PackedValue = Pack(ref vector); /// public ushort PackedValue { get; set; } @@ -48,11 +46,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Bgr565 left, Bgr565 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgr565 left, Bgr565 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -62,183 +57,112 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Bgr565 left, Bgr565 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgr565 left, Bgr565 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - /// Expands the packed representation into a . - /// The vector components are typically expanded in least to greatest significance order. - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector3 ToVector3() - { - return new Vector3( - ((this.PackedValue >> 11) & 0x1F) * (1F / 31F), - ((this.PackedValue >> 5) & 0x3F) * (1F / 63F), - (this.PackedValue & 0x1F) * (1F / 31F)); - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z); + var vector3 = new Vector3(vector.X, vector.Y, vector.Z); + this.PackedValue = Pack(ref vector3); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToVector3(), 1F); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToVector3(), 1F); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromVector4(source.ToVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromVector4(source.ToVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromVector4(source.ToVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) + /// + /// Expands the packed representation into a . + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public Vector3 ToVector3() { - return obj is Bgr565 other && this.Equals(other); + return new Vector3( + ((this.PackedValue >> 11) & 0x1F) * (1F / 31F), + ((this.PackedValue >> 5) & 0x3F) * (1F / 63F), + (this.PackedValue & 0x1F) * (1F / 31F)); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Bgr565 other) - { - return this.PackedValue == other.PackedValue; - } + public override bool Equals(object obj) => obj is Bgr565 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Bgr565 other) => this.PackedValue.Equals(other.PackedValue); /// public override string ToString() { - return this.ToVector3().ToString(); + var vector = this.ToVector3(); + return FormattableString.Invariant($"Bgr565({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##})"); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ushort Pack(float x, float y, float z) + [MethodImpl(InliningOptions.ShortMethod)] + private static ushort Pack(ref Vector3 vector) { - return (ushort)((((int)Math.Round(x.Clamp(0, 1) * 31F) & 0x1F) << 11) - | (((int)Math.Round(y.Clamp(0, 1) * 63F) & 0x3F) << 5) - | ((int)Math.Round(z.Clamp(0, 1) * 31F) & 0x1F)); + vector = Vector3.Clamp(vector, Vector3.Zero, Vector3.One); + + return (ushort)((((int)Math.Round(vector.X * 31F) & 0x1F) << 11) + | (((int)Math.Round(vector.Y * 63F) & 0x3F) << 5) + | ((int)Math.Round(vector.Z * 31F) & 0x1F)); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/Bgra32.cs index ff52600081..9b0ed4f96d 100644 --- a/src/ImageSharp/PixelFormats/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/Bgra32.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// [StructLayout(LayoutKind.Sequential)] - public struct Bgra32 : IPixel, IPackedVector + public partial struct Bgra32 : IPixel, IPackedVector { /// /// Gets or sets the blue component. @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The red component. /// The green component. /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Bgra32(byte r, byte g, byte b) { this.R = r; @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Bgra32(byte r, byte g, byte b, byte a) { this.R = r; @@ -84,10 +84,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// public uint Bgra { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } @@ -98,62 +98,50 @@ namespace SixLabors.ImageSharp.PixelFormats set => this.Bgra = value; } - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - public bool Equals(Bgra32 other) - { - return this.Bgra == other.Bgra; - } - - /// - public override bool Equals(object obj) => obj is Bgra32 other && this.Equals(other); - - /// - public override int GetHashCode() => this.Bgra.GetHashCode(); + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgra32 left, Bgra32 right) => left.Equals(right); /// - /// Gets the representation without normalizing to [0, 1] + /// Compares two objects for equality. /// - /// A of values in [0, 255] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Vector4 ToByteScaledVector4() - { - return new Vector4(this.R, this.G, this.B, this.A); - } + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgra32 left, Bgra32 right) => !left.Equals(right); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.Pack(ref vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) { this.R = source.R; this.G = source.G; @@ -162,113 +150,101 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) { this.R = source.R; this.G = source.G; this.B = source.B; - this.A = source.A; + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackedValue = source.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this = source; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) => dest = Unsafe.As(ref this); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) => dest = this; + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = byte.MaxValue; + } - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A); - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Argb32 ToArgb32() => new Argb32(this.R, this.G, this.B, this.A); - - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Bgra32 ToBgra32() => this; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - this.A = (byte)(((source.A * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); + this.A = ImageMaths.DownScaleFrom16BitTo8Bit(source.A); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + public override bool Equals(object obj) => obj is Bgra32 other && this.Equals(other); + + /// + public bool Equals(Bgra32 other) => this.Bgra.Equals(other.Bgra); + + /// + public override int GetHashCode() => this.Bgra.GetHashCode(); + + /// + public override string ToString() => $"Bgra32({this.B}, {this.G}, {this.R}, {this.A})"; /// /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector4 vector) { vector *= MaxBytes; @@ -280,11 +256,5 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = (byte)vector.Z; this.A = (byte)vector.W; } - - /// - public override string ToString() - { - return $"({this.B},{this.G},{this.R},{this.A})"; - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/Bgra4444.cs index 90f967f898..db1c8f865a 100644 --- a/src/ImageSharp/PixelFormats/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/Bgra4444.cs @@ -23,18 +23,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component /// The w-component public Bgra4444(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - this.PackedValue = Pack(x, y, z, w); } /// /// Initializes a new instance of the struct. /// /// The vector containing the components for the packed vector. - public Bgra4444(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + public Bgra4444(Vector4 vector) => this.PackedValue = Pack(ref vector); /// public ushort PackedValue { get; set; } @@ -47,11 +44,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Bgra4444 left, Bgra4444 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgra4444 left, Bgra4444 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -61,177 +55,103 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Bgra4444 left, Bgra4444 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgra4444 left, Bgra4444 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { const float Max = 1 / 15F; return new Vector4( - ((this.PackedValue >> 8) & 0x0F) * Max, - ((this.PackedValue >> 4) & 0x0F) * Max, - (this.PackedValue & 0x0F) * Max, - ((this.PackedValue >> 12) & 0x0F) * Max); + (this.PackedValue >> 8) & 0x0F, + (this.PackedValue >> 4) & 0x0F, + this.PackedValue & 0x0F, + (this.PackedValue >> 12) & 0x0F) * Max; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is Bgra4444 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Bgra4444 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Bgra4444 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Bgra4444 other) => this.PackedValue.Equals(other.PackedValue); /// public override string ToString() { - return this.ToVector4().ToString(); + var vector = this.ToVector4(); + return FormattableString.Invariant($"Bgra4444({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ushort Pack(float x, float y, float z, float w) + [MethodImpl(InliningOptions.ShortMethod)] + private static ushort Pack(ref Vector4 vector) { - return (ushort)((((int)Math.Round(w.Clamp(0, 1) * 15F) & 0x0F) << 12) | - (((int)Math.Round(x.Clamp(0, 1) * 15F) & 0x0F) << 8) | - (((int)Math.Round(y.Clamp(0, 1) * 15F) & 0x0F) << 4) | - ((int)Math.Round(z.Clamp(0, 1) * 15F) & 0x0F)); + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); + return (ushort)((((int)Math.Round(vector.W * 15F) & 0x0F) << 12) + | (((int)Math.Round(vector.X * 15F) & 0x0F) << 8) + | (((int)Math.Round(vector.Y * 15F) & 0x0F) << 4) + | ((int)Math.Round(vector.Z * 15F) & 0x0F)); } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs index 3a18c03e83..5d9003cdd3 100644 --- a/src/ImageSharp/PixelFormats/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/Bgra5551.cs @@ -8,7 +8,8 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.PixelFormats { /// - /// Packed pixel type containing unsigned normalized values ranging from 0 to 1. The x , y and z components use 5 bits, and the w component uses 1 bit. + /// Packed pixel type containing unsigned normalized values ranging from 0 to 1. + /// The x , y and z components use 5 bits, and the w component uses 1 bit. /// /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. /// @@ -23,8 +24,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component /// The w-component public Bgra5551(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - this.PackedValue = Pack(x, y, z, w); } /// @@ -33,10 +34,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed vector. /// - public Bgra5551(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + public Bgra5551(Vector4 vector) => this.PackedValue = Pack(ref vector); /// public ushort PackedValue { get; set; } @@ -49,11 +47,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Bgra5551 left, Bgra5551 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgra5551 left, Bgra5551 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -63,31 +58,26 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Bgra5551 left, Bgra5551 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgra5551 left, Bgra5551 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { return new Vector4( @@ -98,150 +88,72 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is Bgra5551 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Bgra5551 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Bgra5551 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Bgra5551 other) => this.PackedValue.Equals(other.PackedValue); - /// - /// Gets a string representation of the packed vector. - /// - /// A string representation of the packed vector. + /// public override string ToString() { - return this.ToVector4().ToString(); + var vector = this.ToVector4(); + return FormattableString.Invariant($"Bgra5551({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"); } - /// - /// Gets a hash code of the packed vector. - /// - /// The hash code for the packed vector. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ushort Pack(float x, float y, float z, float w) + [MethodImpl(InliningOptions.ShortMethod)] + private static ushort Pack(ref Vector4 vector) { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); return (ushort)( - (((int)Math.Round(x.Clamp(0, 1) * 31F) & 0x1F) << 10) - | (((int)Math.Round(y.Clamp(0, 1) * 31F) & 0x1F) << 5) - | (((int)Math.Round(z.Clamp(0, 1) * 31F) & 0x1F) << 0) - | (((int)Math.Round(w.Clamp(0, 1)) & 0x1) << 15)); + (((int)Math.Round(vector.X * 31F) & 0x1F) << 10) + | (((int)Math.Round(vector.Y * 31F) & 0x1F) << 5) + | (((int)Math.Round(vector.Z * 31F) & 0x1F) << 0) + | (((int)Math.Round(vector.W) & 0x1) << 15)); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() => this.ToVector4() * 255f; } -} +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/Byte4.cs index bb1b350f07..230c31c5c3 100644 --- a/src/ImageSharp/PixelFormats/Byte4.cs +++ b/src/ImageSharp/PixelFormats/Byte4.cs @@ -21,10 +21,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// A vector containing the initial values for the components of the Byte4 structure. /// - public Byte4(Vector4 vector) - { - this.PackedValue = Pack(ref vector); - } + public Byte4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// /// Initializes a new instance of the struct. @@ -50,11 +47,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Byte4 left, Byte4 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Byte4 left, Byte4 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -64,38 +58,26 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Byte4 left, Byte4 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Byte4 left, Byte4 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector * 255F); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector * 255F); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4() / 255F; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4() / 255F; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(ref vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { return new Vector4( @@ -106,119 +88,61 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToByteScaledVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToByteScaledVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToByteScaledVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is Byte4 byte4 && this.Equals(byte4); - } + public override bool Equals(object obj) => obj is Byte4 byte4 && this.Equals(byte4); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Byte4 other) - { - return this == other; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Byte4 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Returns a string representation of the current instance. - /// - /// String that represents the object. + /// public override string ToString() { - return this.PackedValue.ToString("x8"); + var vector = this.ToVector4(); + return FormattableString.Invariant($"Bgra5551({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } /// @@ -226,18 +150,18 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the values to pack. /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static uint Pack(ref Vector4 vector) { const float Max = 255F; - const float Min = 0F; // Clamp the value between min and max values - // TODO: Use Vector4.Clamp() here! - uint byte4 = (uint)Math.Round(vector.X.Clamp(Min, Max)) & 0xFF; - uint byte3 = ((uint)Math.Round(vector.Y.Clamp(Min, Max)) & 0xFF) << 0x8; - uint byte2 = ((uint)Math.Round(vector.Z.Clamp(Min, Max)) & 0xFF) << 0x10; - uint byte1 = ((uint)Math.Round(vector.W.Clamp(Min, Max)) & 0xFF) << 0x18; + vector = Vector4.Clamp(vector, Vector4.Zero, new Vector4(Max)); + + uint byte4 = (uint)Math.Round(vector.X) & 0xFF; + uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 0x8; + uint byte2 = ((uint)Math.Round(vector.Z) & 0xFF) << 0x10; + uint byte1 = ((uint)Math.Round(vector.W) & 0xFF) << 0x18; return byte4 | byte3 | byte2 | byte1; } diff --git a/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.cs new file mode 100644 index 0000000000..0b40df8dae --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Argb32 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.tt new file mode 100644 index 0000000000..f35adee022 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Argb32 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.cs new file mode 100644 index 0000000000..e895254576 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Bgr24 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.tt new file mode 100644 index 0000000000..76163549b0 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Bgr24 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.cs new file mode 100644 index 0000000000..2311e0bde6 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Bgra32 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.tt new file mode 100644 index 0000000000..4c2925d18f --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Bgra32 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.cs new file mode 100644 index 0000000000..a2d9aa755f --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Gray16 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromGray16(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.tt new file mode 100644 index 0000000000..b900e343a7 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Gray16 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromGray16(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.cs new file mode 100644 index 0000000000..de2c11d4d9 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Gray8 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromGray8(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.tt new file mode 100644 index 0000000000..4590420e57 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Gray8 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromGray8(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs index e8908fe05e..66966543fc 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs @@ -10,296 +10,357 @@ namespace SixLabors.ImageSharp.PixelFormats public partial class PixelOperations { - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; + ref Argb32 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba64(temp); + ref Argb32 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromArgb32(sp); } } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromRgba64Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromArgb32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromRgba64(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromArgb32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . + + /// + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToRgba64(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Argb32 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToRgba64(ref dp); + ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } - /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgba64Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToArgb32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba64(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToArgb32(sourcePixels, MemoryMarshal.Cast(destBytes), count); } - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + + /// + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; + ref Bgr24 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgb48(temp); + ref Bgr24 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromBgr24(sp); } } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromRgb48Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromBgr24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromRgb48(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromBgr24(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . + + /// + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToRgb48(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Bgr24 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToRgb48(ref dp); + ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } - /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgb48Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToBgr24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb48(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToBgr24(sourcePixels, MemoryMarshal.Cast(destBytes), count); } - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + + /// + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; + ref Bgra32 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba32(temp); + ref Bgra32 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromBgra32(sp); } } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromRgba32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromBgra32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromRgba32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromBgra32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . + + /// + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToRgba32(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Bgra32 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToRgba32(ref dp); + ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } - /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgba32Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToBgra32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba32(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToBgra32(sourcePixels, MemoryMarshal.Cast(destBytes), count); } - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + + /// + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromGray8(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + ref Gray8 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void PackFromGray8Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + { + this.PackFromGray8(MemoryMarshal.Cast(sourceBytes), destPixels, count); + } + + /// + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// + /// The span of source pixels + /// The destination span of data. + /// The number of pixels to convert. + internal virtual void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromBgra32(temp); + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// The to the source pixels. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToGray8Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + { + this.ToGray8(sourcePixels, MemoryMarshal.Cast(destBytes), count); + } + + /// + /// Converts 'count' elements in 'source` span of data to a span of -s. + /// + /// The source of data. + /// The to the destination pixels. + /// The number of pixels to convert. + internal virtual void PackFromGray16(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + ref Gray16 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromBgra32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromGray16Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromBgra32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromGray16(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . + + /// + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToBgra32(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Gray16 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToBgra32(ref dp); + ref Gray16 dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } - /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToBgra32Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToGray16Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgra32(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToGray16(sourcePixels, MemoryMarshal.Cast(destBytes), count); } - - /// + + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// /// The source of data. @@ -307,23 +368,21 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; + ref Rgb24 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp.Rgb = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba32(temp); + ref Rgb24 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromRgb24(sp); } } - - /// + + /// /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// @@ -335,186 +394,250 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromRgb24(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// + + /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToRgb24(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Rgb24 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToRgb24(ref dp); + + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } - /// + /// /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgb24Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToRgb24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb24(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToRgb24(sourcePixels, MemoryMarshal.Cast(destBytes), count); } - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + + /// + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; + ref Rgba32 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp.Bgr = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba32(temp); + ref Rgba32 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromRgba32(sp); } } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromBgr24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromRgba32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromBgr24(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromRgba32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . + + /// + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToBgr24(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Rgba32 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToBgr24(ref dp); + ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } - /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToBgr24Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToRgba32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgr24(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToRgba32(sourcePixels, MemoryMarshal.Cast(destBytes), count); } - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + + /// + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; + ref Rgb48 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromArgb32(temp); + ref Rgb48 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromRgb48(sp); } } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromArgb32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromRgb48Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromArgb32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromRgb48(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . + + /// + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToArgb32(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Rgb48 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToArgb32(ref dp); + ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } - /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToArgb32Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToRgb48Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + { + this.ToRgb48(sourcePixels, MemoryMarshal.Cast(destBytes), count); + } + + /// + /// Converts 'count' elements in 'source` span of data to a span of -s. + /// + /// The source of data. + /// The to the destination pixels. + /// The number of pixels to convert. + internal virtual void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void PackFromRgba64Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + { + this.PackFromRgba64(MemoryMarshal.Cast(sourceBytes), destPixels, count); + } + + /// + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// + /// The span of source pixels + /// The destination span of data. + /// The number of pixels to convert. + internal virtual void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) { - this.ToArgb32(sourceColors, MemoryMarshal.Cast(destBytes), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromScaledVector4(sp.ToScaledVector4()); + } } - - } + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// The to the source pixels. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToRgba64Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + { + this.ToRgba64(sourcePixels, MemoryMarshal.Cast(destBytes), count); + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt index 5c762c7df1..913dabb087 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt @@ -11,11 +11,11 @@ <#@ output extension=".cs" #> <# - void GeneratePackFromMethods(string pixelType, string tempPixelType, string assignToTempCode) + void GeneratePackFromMethods(string pixelType) { #> - /// + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// /// The source of data. @@ -23,23 +23,21 @@ /// The number of pixels to convert. internal virtual void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors<<#=tempPixelType#>>.Black; + ref <#=pixelType#> sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - <#=assignToTempCode#> - dp.PackFrom<#=tempPixelType#>(temp); + ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFrom<#=pixelType#>(sp); } } - - /// + + /// /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// @@ -51,48 +49,48 @@ { this.PackFrom<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); } - <# + +<# } void GenerateToDestFormatMethods(string pixelType) { #> - - /// + /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> dest, int count) + internal virtual void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destBaseRef = ref MemoryMarshal.GetReference(dest); + ref <#=pixelType#> destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i); - sp.To<#=pixelType#>(ref dp); + + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } - /// + /// /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void To<#=pixelType#>Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void To<#=pixelType#>Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.To<#=pixelType#>(sourceColors, MemoryMarshal.Cast>(destBytes), count); + this.To<#=pixelType#>(sourcePixels, MemoryMarshal.Cast>(destBytes), count); } - <# +<# } #> @@ -107,30 +105,34 @@ namespace SixLabors.ImageSharp.PixelFormats using System.Runtime.InteropServices; public partial class PixelOperations - { - <# - GeneratePackFromMethods("Rgba64", "Rgba64", "temp = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Rgba64"); + {<# - GeneratePackFromMethods("Rgb48", "Rgb48", "temp = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Rgb48"); + GeneratePackFromMethods("Argb32"); + GenerateToDestFormatMethods("Argb32"); - GeneratePackFromMethods("Rgba32", "Rgba32", "temp = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Rgba32"); + GeneratePackFromMethods("Bgr24"); + GenerateToDestFormatMethods("Bgr24"); - GeneratePackFromMethods("Bgra32", "Bgra32", "temp = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Bgra32"); GenerateToDestFormatMethods("Bgra32"); - - GeneratePackFromMethods("Rgb24", "Rgba32", "temp.Rgb = Unsafe.Add(ref sourceRef, i);"); + + GeneratePackFromMethods("Gray8"); + GenerateToDestFormatMethods("Gray8"); + + GeneratePackFromMethods("Gray16"); + GenerateToDestFormatMethods("Gray16"); + + GeneratePackFromMethods("Rgb24"); GenerateToDestFormatMethods("Rgb24"); - GeneratePackFromMethods("Bgr24", "Rgba32", "temp.Bgr = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Bgr24"); + GeneratePackFromMethods("Rgba32"); + GenerateToDestFormatMethods("Rgba32"); - GeneratePackFromMethods("Argb32", "Argb32", "temp = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Argb32"); - #> + GeneratePackFromMethods("Rgb48"); + GenerateToDestFormatMethods("Rgb48"); - } + GeneratePackFromMethods("Rgba64"); + GenerateToDestFormatMethods("Rgba64"); +#> } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.cs new file mode 100644 index 0000000000..ad4ee2764e --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgb24 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.tt new file mode 100644 index 0000000000..6a10b401f4 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgb24 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.cs new file mode 100644 index 0000000000..0a1ef03873 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgb48 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.tt new file mode 100644 index 0000000000..e38c85bf62 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgb48 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs index e68efba252..bd3e014b4d 100644 --- a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs @@ -13,134 +13,162 @@ namespace SixLabors.ImageSharp.PixelFormats /// public partial struct Rgba32 { + + /// + /// Provides optimized overrides for bulk operations. + /// internal partial class PixelOperations { + /// + internal override void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + /// - internal override void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - Unsafe.As(ref dp) = sp; dp.A = 255; + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span dest, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(dest); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp = Unsafe.As(ref sp); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } /// - internal override void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.Bgr = sp; dp.A = 255; + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span dest, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(dest); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.Bgr; + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } /// - internal override void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToRgba32(); + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span dest, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(dest); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToBgra32(); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } /// - internal override void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToRgba32(); + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span dest, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(dest); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToArgb32(); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt index a734333390..23d0be740e 100644 --- a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt @@ -9,45 +9,24 @@ <#@ import namespace="System.Collections.Generic" #> <#@ output extension=".cs" #> <# - void GeneratePackFromMethod(string pixelType, string converterCode) + void GenerateConvertToMethod(string pixelType) { #> /// - internal override void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - - for (int i = 0; i < count; i++) - { - ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - <#=converterCode#> - } - } - <# - } - - void GenerateConvertToMethod(string pixelType, string converterCode) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(dest); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - <#=converterCode#> + + dp.PackFromRgba32(sp); } } <# @@ -68,20 +47,37 @@ namespace SixLabors.ImageSharp.PixelFormats /// public partial struct Rgba32 { + + /// + /// Provides optimized overrides for bulk operations. + /// internal partial class PixelOperations { - <# - GeneratePackFromMethod("Rgb24", "Unsafe.As(ref dp) = sp; dp.A = 255;"); - GenerateConvertToMethod("Rgb24", "dp = Unsafe.As(ref sp);"); + /// + internal override void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - GeneratePackFromMethod("Bgr24", "dp.Bgr = sp; dp.A = 255;"); - GenerateConvertToMethod("Bgr24", "dp = sp.Bgr;"); - - GeneratePackFromMethod("Bgra32", "dp = sp.ToRgba32();"); - GenerateConvertToMethod("Bgra32", "dp = sp.ToBgra32();"); + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - GeneratePackFromMethod("Argb32", "dp = sp.ToRgba32();"); - GenerateConvertToMethod("Argb32", "dp = sp.ToArgb32();"); + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); #> } diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.cs new file mode 100644 index 0000000000..e6f9b37a70 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgba64 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.tt new file mode 100644 index 0000000000..e998341570 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgba64 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Gray16.cs b/src/ImageSharp/PixelFormats/Gray16.cs new file mode 100644 index 0000000000..34f221d79c --- /dev/null +++ b/src/ImageSharp/PixelFormats/Gray16.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing a single 16 bit normalized gray values. + /// + /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. + /// + /// + public partial struct Gray16 : IPixel, IPackedVector + { + private const float Max = ushort.MaxValue; + private const float Average = 1 / 3F; + + /// + /// Initializes a new instance of the struct. + /// + /// The luminance component + public Gray16(ushort luminance) => this.PackedValue = luminance; + + /// + public ushort PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Gray16 left, Gray16 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Gray16 left, Gray16 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) + { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max * Average; + this.PackedValue = (ushort)MathF.Round(vector.X + vector.Y + vector.Z); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() + { + float scaled = this.PackedValue / Max; + return new Vector4(scaled, scaled, scaled, 1F); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) + { + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) + { + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) + { + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackedValue = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackedValue = source.PackedValue; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) + { + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) + { + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() + { + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(this.PackedValue); + return new Rgba32(rgb, rgb, rgb, byte.MaxValue); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba64(Rgba64 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); + + /// + public override bool Equals(object obj) => obj is Gray16 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Gray16 other) => this.PackedValue.Equals(other.PackedValue); + + /// + public override string ToString() => $"Gray16({this.PackedValue})"; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + [MethodImpl(InliningOptions.ShortMethod)] + internal void ConvertFromRgbaScaledVector4(Vector4 vector) + { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + (ushort)MathF.Round(vector.X), + (ushort)MathF.Round(vector.Y), + (ushort)MathF.Round(vector.Z)); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Gray8.cs b/src/ImageSharp/PixelFormats/Gray8.cs new file mode 100644 index 0000000000..5812405876 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Gray8.cs @@ -0,0 +1,152 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing a single 8 bit normalized gray values. + /// + /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. + /// + /// + public partial struct Gray8 : IPixel, IPackedVector + { + private static readonly Vector4 MaxBytes = new Vector4(255F); + private static readonly Vector4 Half = new Vector4(0.5F); + private const float Average = 1 / 3F; + + /// + /// Initializes a new instance of the struct. + /// + /// The luminance component. + public Gray8(byte luminance) => this.PackedValue = luminance; + + /// + public byte PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Gray8 left, Gray8 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Gray8 left, Gray8 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) + { + vector *= MaxBytes; + vector += Half; + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes) * Average; + this.PackedValue = (byte)(vector.X + vector.Y + vector.Z); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() + { + float rgb = this.PackedValue / 255F; + return new Vector4(rgb, rgb, rgb, 1F); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackedValue = source.PackedValue; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackedValue = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.PackedValue, this.PackedValue, this.PackedValue, byte.MaxValue); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) + => this.PackedValue = ImageMaths.Get8BitBT709Luminance( + ImageMaths.DownScaleFrom16BitTo8Bit(source.R), + ImageMaths.DownScaleFrom16BitTo8Bit(source.G), + ImageMaths.DownScaleFrom16BitTo8Bit(source.B)); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba64(Rgba64 source) + => this.PackedValue = ImageMaths.Get8BitBT709Luminance( + ImageMaths.DownScaleFrom16BitTo8Bit(source.R), + ImageMaths.DownScaleFrom16BitTo8Bit(source.G), + ImageMaths.DownScaleFrom16BitTo8Bit(source.B)); + + /// + public override bool Equals(object obj) => obj is Gray8 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Gray8 other) => this.PackedValue.Equals(other.PackedValue); + + /// + public override string ToString() => $"Gray8({this.PackedValue}"; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + [MethodImpl(InliningOptions.ShortMethod)] + internal void ConvertFromRgbaScaledVector4(Vector4 vector) + { + vector *= MaxBytes; + vector += Half; + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + this.PackedValue = ImageMaths.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/HalfSingle.cs index 09b4636492..bef4a5dd9b 100644 --- a/src/ImageSharp/PixelFormats/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/HalfSingle.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; @@ -14,24 +15,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct HalfSingle : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half vector value. - /// - private static readonly Vector4 Half = new Vector4(0.5F); - /// /// Initializes a new instance of the struct. /// /// The single component. - public HalfSingle(float single) - { - this.PackedValue = HalfTypeHelper.Pack(single); - } + public HalfSingle(float single) => this.PackedValue = HalfTypeHelper.Pack(single); /// public ushort PackedValue { get; set; } @@ -39,206 +27,114 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(HalfSingle left, HalfSingle right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(HalfSingle left, HalfSingle right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(HalfSingle left, HalfSingle right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(HalfSingle left, HalfSingle right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - /// Expands the packed representation into a . - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float ToSingle() - { - return HalfTypeHelper.Unpack(this.PackedValue); - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { float scaled = vector.X; scaled *= 2F; - scaled -= 1F; + scaled--; this.PackedValue = HalfTypeHelper.Pack(scaled); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { float single = this.ToSingle() + 1F; single /= 2F; - return new Vector4(single, 0, 0, 1); + return new Vector4(single, 0, 0, 1F); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = HalfTypeHelper.Pack(vector.X); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = HalfTypeHelper.Pack(vector.X); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToSingle(), 0, 0, 1); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToSingle(), 0, 0, 1F); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + /// Expands the packed representation into a . + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public float ToSingle() => HalfTypeHelper.Unpack(this.PackedValue); /// - public override bool Equals(object obj) - { - return obj is HalfSingle other && this.Equals(other); - } + public override bool Equals(object obj) => obj is HalfSingle other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(HalfSingle other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(HalfSingle other) => this.PackedValue.Equals(other.PackedValue); /// - public override string ToString() - { - return this.ToSingle().ToString(); - } + public override string ToString() => FormattableString.Invariant($"HalfSingle({this.ToSingle():#0.##})"); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/HalfTypeHelper.cs b/src/ImageSharp/PixelFormats/HalfTypeHelper.cs index cf8b9f4a23..e8cfaa462e 100644 --- a/src/ImageSharp/PixelFormats/HalfTypeHelper.cs +++ b/src/ImageSharp/PixelFormats/HalfTypeHelper.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Helper methods for packing and unpacking floating point values /// - internal class HalfTypeHelper + internal static class HalfTypeHelper { /// /// Packs a into an @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.PixelFormats return (ushort)s; } - m = m | 0x00800000; + m |= 0x00800000; int t = 14 - e; int a = (1 << (t - 1)) - 1; @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.PixelFormats if ((m & 0x00800000) != 0) { m = 0; - e += 1; + e++; } if (e > 30) @@ -97,11 +97,11 @@ namespace SixLabors.ImageSharp.PixelFormats while ((mantissa & 1024) == 0) { exponent--; - mantissa = mantissa << 1; + mantissa <<= 1; } mantissa &= 0xfffffbff; - result = ((uint)((((uint)value & 0x8000) << 16) | ((exponent + 127) << 23))) | (mantissa << 13); + result = (((uint)value & 0x8000) << 16) | ((exponent + 127) << 23) | (mantissa << 13); } else { @@ -110,7 +110,7 @@ namespace SixLabors.ImageSharp.PixelFormats } else { - result = ((((uint)value & 0x8000) << 16) | ((((((uint)value >> 10) & 0x1f) - 15) + 127) << 23)) | (mantissa << 13); + result = (((uint)value & 0x8000) << 16) | ((((((uint)value >> 10) & 0x1f) - 15) + 127) << 23) | (mantissa << 13); } var uif = new Uif { U = result }; diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/HalfVector2.cs index befa49736c..5bd9924c53 100644 --- a/src/ImageSharp/PixelFormats/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/HalfVector2.cs @@ -15,34 +15,18 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct HalfVector2 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half vector value. - /// - private static readonly Vector4 Half = new Vector4(0.5F); - /// /// Initializes a new instance of the struct. /// /// The x-component. /// The y-component. - public HalfVector2(float x, float y) - { - this.PackedValue = Pack(x, y); - } + public HalfVector2(float x, float y) => this.PackedValue = Pack(x, y); /// /// Initializes a new instance of the struct. /// /// A vector containing the initial values for the components. - public HalfVector2(Vector2 vector) - { - this.PackedValue = Pack(vector.X, vector.Y); - } + public HalfVector2(Vector2 vector) => this.PackedValue = Pack(vector.X, vector.Y); /// public uint PackedValue { get; set; } @@ -50,57 +34,30 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(HalfVector2 left, HalfVector2 right) - { - return left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(HalfVector2 left, HalfVector2 right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(HalfVector2 left, HalfVector2 right) - { - return !left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(HalfVector2 left, HalfVector2 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - /// Expands the packed representation into a . - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector2 ToVector2() - { - Vector2 vector; - vector.X = HalfTypeHelper.Unpack((ushort)this.PackedValue); - vector.Y = HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10)); - return vector; - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; @@ -109,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector2(); @@ -119,14 +76,11 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(vector.X, vector.Y); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { var vector = this.ToVector2(); @@ -134,140 +88,82 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override string ToString() + /// + /// Expands the packed representation into a . + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public Vector2 ToVector2() { - return this.ToVector2().ToString(); + Vector2 vector; + vector.X = HalfTypeHelper.Unpack((ushort)this.PackedValue); + vector.Y = HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10)); + return vector; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.PackedValue.GetHashCode(); + public override bool Equals(object obj) => obj is HalfVector2 other && this.Equals(other); /// - public override bool Equals(object obj) - { - return obj is HalfVector2 other && this.Equals(other); - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(HalfVector2 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(HalfVector2 other) + public override string ToString() { - return this.PackedValue.Equals(other.PackedValue); + var vector = this.ToVector2(); + return FormattableString.Invariant($"HalfVector2({vector.X:#0.##}, {vector.Y:#0.##})"); } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + [MethodImpl(InliningOptions.ShortMethod)] private static uint Pack(float x, float y) { uint num2 = HalfTypeHelper.Pack(x); uint num = (uint)(HalfTypeHelper.Pack(y) << 0x10); return num2 | num; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs index 885e022921..2e487ef985 100644 --- a/src/ImageSharp/PixelFormats/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/HalfVector4.cs @@ -15,16 +15,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct HalfVector4 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half vector value. - /// - private static readonly Vector4 Half = new Vector4(0.5F); - /// /// Initializes a new instance of the struct. /// @@ -33,64 +23,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component. /// The w-component. public HalfVector4(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - var vector = new Vector4(x, y, z, w); - this.PackedValue = Pack(ref vector); } /// /// Initializes a new instance of the struct. /// /// A vector containing the initial values for the components - public HalfVector4(Vector4 vector) - { - this.PackedValue = Pack(ref vector); - } + public HalfVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// public ulong PackedValue { get; set; } /// - /// Compares two objects for equality. + /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(HalfVector4 left, HalfVector4 right) - { - return left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(HalfVector4 left, HalfVector4 right) => left.Equals(right); /// - /// Compares two objects for equality. + /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(HalfVector4 left, HalfVector4 right) - { - return !left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(HalfVector4 left, HalfVector4 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { vector *= 2F; @@ -99,7 +71,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector4(); @@ -109,14 +81,11 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(ref vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { return new Vector4( @@ -127,124 +96,69 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override string ToString() - { - return this.ToVector4().ToString(); - } + public override bool Equals(object obj) => obj is HalfVector4 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.PackedValue.GetHashCode(); + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(HalfVector4 other) => this.PackedValue.Equals(other.PackedValue); /// - public override bool Equals(object obj) + public override string ToString() { - return obj is HalfVector4 other && this.Equals(other); + var vector = this.ToVector4(); + return FormattableString.Invariant($"HalfVector4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(HalfVector4 other) - { - return this.PackedValue.Equals(other.PackedValue); - } + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// /// Packs a into a . /// /// The vector containing the values to pack. /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static ulong Pack(ref Vector4 vector) { ulong num4 = HalfTypeHelper.Pack(vector.X); @@ -253,15 +167,5 @@ namespace SixLabors.ImageSharp.PixelFormats ulong num1 = (ulong)HalfTypeHelper.Pack(vector.W) << 0x30; return num4 | num3 | num2 | num1; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index ae09af626c..87125fa0a3 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -28,12 +28,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// public interface IPixel { - /// - /// Sets the packed representation from a . - /// - /// The vector to create the packed representation from. - void PackFromVector4(Vector4 vector); - /// /// Sets the packed representation from a scaled . /// @@ -48,6 +42,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// The . Vector4 ToScaledVector4(); + /// + /// Sets the packed representation from a . + /// + /// The vector to create the packed representation from. + void PackFromVector4(Vector4 vector); + /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. @@ -55,30 +55,18 @@ namespace SixLabors.ImageSharp.PixelFormats /// The . Vector4 ToVector4(); - /// - /// Packs the pixel from an value. - /// - /// The value. - void PackFromRgba32(Rgba32 source); - - /// - /// Packs the pixel from an value. - /// - /// The value. - void PackFromRgb48(Rgb48 source); - - /// - /// Packs the pixel from an value. - /// - /// The value. - void PackFromRgba64(Rgba64 source); - /// /// Packs the pixel from an value. /// /// The value. void PackFromArgb32(Argb32 source); + /// + /// Packs the pixel from an value. + /// + /// The value. + void PackFromBgr24(Bgr24 source); + /// /// Packs the pixel from an value. /// @@ -86,45 +74,45 @@ namespace SixLabors.ImageSharp.PixelFormats void PackFromBgra32(Bgra32 source); /// - /// Converts the pixel to format. + /// Packs the Pixel from an value. /// - /// The destination pixel to write to - void ToRgb24(ref Rgb24 dest); + /// The value. + void PackFromGray8(Gray8 source); /// - /// Converts the pixel to format. + /// Packs the Pixel from an value. /// - /// The destination pixel to write to - void ToRgba32(ref Rgba32 dest); + /// The value. + void PackFromGray16(Gray16 source); /// - /// Converts the pixel to format. + /// Packs the pixel from an value. /// - /// The destination pixel to write to - void ToRgb48(ref Rgb48 dest); + /// The value. + void PackFromRgb24(Rgb24 source); /// - /// Converts the pixel to format. + /// Packs the pixel from an value. /// - /// The destination pixel to write to - void ToRgba64(ref Rgba64 dest); + /// The value. + void PackFromRgba32(Rgba32 source); /// - /// Converts the pixel to format. + /// Expands the packed representation into an . /// - /// The destination pixel to write to - void ToArgb32(ref Argb32 dest); + /// The . + Rgba32 ToRgba32(); /// - /// Converts the pixel to format. + /// Packs the pixel from an value. /// - /// The destination pixel to write to - void ToBgr24(ref Bgr24 dest); + /// The value. + void PackFromRgb48(Rgb48 source); /// - /// Converts the pixel to format. + /// Packs the pixel from an value. /// - /// The destination pixel to write to - void ToBgra32(ref Bgra32 dest); + /// The value. + void PackFromRgba64(Rgba64 source); } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs index 8592fdd6a7..219ec87630 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte2.cs @@ -15,39 +15,24 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct NormalizedByte2 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half the maximum byte value. - /// - private static readonly Vector4 Half = new Vector4(127); - - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); + private static readonly Vector2 Half = new Vector2(127); + private static readonly Vector2 MinusOne = new Vector2(-1F); /// /// Initializes a new instance of the struct. /// - /// The vector containing the component values. - public NormalizedByte2(Vector2 vector) + /// The x-component. + /// The y-component. + public NormalizedByte2(float x, float y) + : this(new Vector2(x, y)) { - this.PackedValue = Pack(vector.X, vector.Y); } /// /// Initializes a new instance of the struct. /// - /// The x-component. - /// The y-component. - public NormalizedByte2(float x, float y) - { - this.PackedValue = Pack(x, y); - } + /// The vector containing the component values. + public NormalizedByte2(Vector2 vector) => this.PackedValue = Pack(vector); /// public ushort PackedValue { get; set; } @@ -55,66 +40,39 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(NormalizedByte2 left, NormalizedByte2 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(NormalizedByte2 left, NormalizedByte2 right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(NormalizedByte2 left, NormalizedByte2 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(NormalizedByte2 left, NormalizedByte2 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - /// Expands the packed representation into a . - /// The vector components are typically expanded in least to greatest significance order. - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector2 ToVector2() - { - return new Vector2( - (sbyte)((this.PackedValue >> 0) & 0xFF) / 127F, - (sbyte)((this.PackedValue >> 8) & 0xFF) / 127F); - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; scaled -= Vector2.One; - this.PackedValue = Pack(scaled.X, scaled.Y); + this.PackedValue = Pack(scaled); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector2(); @@ -124,172 +82,97 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y); + var vector2 = new Vector2(vector.X, vector.Y); + this.PackedValue = Pack(vector2); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToVector2(), 0F, 1F); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToVector2(), 0F, 1F); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) + /// + /// Expands the packed representation into a . + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public Vector2 ToVector2() { - return obj is NormalizedByte2 other && this.Equals(other); + return new Vector2( + (sbyte)((this.PackedValue >> 0) & 0xFF) / 127F, + (sbyte)((this.PackedValue >> 8) & 0xFF) / 127F); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(NormalizedByte2 other) - { - return this.PackedValue == other.PackedValue; - } + public override bool Equals(object obj) => obj is NormalizedByte2 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(NormalizedByte2 other) => this.PackedValue.Equals(other.PackedValue); + + /// + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override string ToString() { - return this.PackedValue.ToString("X"); + var vector = this.ToVector2(); + return FormattableString.Invariant($"NormalizedByte2({vector.X:#0.##}, {vector.Y:#0.##})"); } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ushort Pack(float x, float y) + [MethodImpl(InliningOptions.ShortMethod)] + private static ushort Pack(Vector2 vector) { - int byte2 = ((ushort)Math.Round(x.Clamp(-1F, 1F) * 127F) & 0xFF) << 0; - int byte1 = ((ushort)Math.Round(y.Clamp(-1F, 1F) * 127F) & 0xFF) << 8; + vector = Vector2.Clamp(vector, MinusOne, Vector2.One) * Half; - return (ushort)(byte2 | byte1); - } + int byte2 = ((ushort)Math.Round(vector.X) & 0xFF) << 0; + int byte1 = ((ushort)Math.Round(vector.Y) & 0xFF) << 8; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; + return (ushort)(byte2 | byte1); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/NormalizedByte4.cs index 293d536e53..d5795cb4bd 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte4.cs @@ -15,29 +15,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct NormalizedByte4 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half the maximum byte value. - /// private static readonly Vector4 Half = new Vector4(127); - - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public NormalizedByte4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + private static readonly Vector4 MinusOne = new Vector4(-1F); /// /// Initializes a new instance of the struct. @@ -47,54 +26,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component. /// The w-component. public NormalizedByte4(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - this.PackedValue = Pack(x, y, z, w); } + /// + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public NormalizedByte4(Vector4 vector) => this.PackedValue = Pack(ref vector); + /// public uint PackedValue { get; set; } /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(NormalizedByte4 left, NormalizedByte4 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(NormalizedByte4 left, NormalizedByte4 right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(NormalizedByte4 left, NormalizedByte4 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(NormalizedByte4 left, NormalizedByte4 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { vector *= 2F; @@ -103,7 +74,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector4(); @@ -113,14 +84,11 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { return new Vector4( @@ -131,162 +99,74 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is NormalizedByte4 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is NormalizedByte4 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(NormalizedByte4 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(NormalizedByte4 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override string ToString() { - return this.PackedValue.ToString("X"); + var vector = this.ToVector4(); + return FormattableString.Invariant($"NormalizedByte4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y, float z, float w) + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(ref Vector4 vector) { - uint byte4 = ((uint)Math.Round(x.Clamp(-1F, 1F) * 127F) & 0xFF) << 0; - uint byte3 = ((uint)Math.Round(y.Clamp(-1F, 1F) * 127F) & 0xFF) << 8; - uint byte2 = ((uint)Math.Round(z.Clamp(-1F, 1F) * 127F) & 0xFF) << 16; - uint byte1 = ((uint)Math.Round(w.Clamp(-1F, 1F) * 127F) & 0xFF) << 24; + vector = Vector4.Clamp(vector, MinusOne, Vector4.One) * Half; - return byte4 | byte3 | byte2 | byte1; - } + uint byte4 = ((uint)Math.Round(vector.X) & 0xFF) << 0; + uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 8; + uint byte2 = ((uint)Math.Round(vector.Z) & 0xFF) << 16; + uint byte1 = ((uint)Math.Round(vector.W) & 0xFF) << 24; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; + return byte4 | byte3 | byte2 | byte1; } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/NormalizedShort2.cs index 1ced412d06..34e752496a 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort2.cs @@ -15,39 +15,24 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct NormalizedShort2 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half the maximum byte value. - /// - private static readonly Vector4 Half = new Vector4(127); - - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); + private static readonly Vector2 Max = new Vector2(0x7FFF); + private static readonly Vector2 Min = Vector2.Negate(Max); /// /// Initializes a new instance of the struct. /// - /// The vector containing the component values. - public NormalizedShort2(Vector2 vector) + /// The x-component. + /// The y-component. + public NormalizedShort2(float x, float y) + : this(new Vector2(x, y)) { - this.PackedValue = Pack(vector.X, vector.Y); } /// /// Initializes a new instance of the struct. /// - /// The x-component. - /// The y-component. - public NormalizedShort2(float x, float y) - { - this.PackedValue = Pack(x, y); - } + /// The vector containing the component values. + public NormalizedShort2(Vector2 vector) => this.PackedValue = Pack(vector); /// public uint PackedValue { get; set; } @@ -55,53 +40,39 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(NormalizedShort2 left, NormalizedShort2 right) - { - return left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(NormalizedShort2 left, NormalizedShort2 right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) - { - return !left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; scaled -= Vector2.One; - this.PackedValue = Pack(scaled.X, scaled.Y); + this.PackedValue = Pack(scaled); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector2(); @@ -111,130 +82,63 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y); + var vector2 = new Vector2(vector.X, vector.Y); + this.PackedValue = Pack(vector2); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToVector2(), 0, 1); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToVector2(), 0, 1); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. /// /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector2 ToVector2() { const float MaxVal = 0x7FFF; @@ -245,61 +149,34 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - public override bool Equals(object obj) - { - return obj is NormalizedShort2 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is NormalizedShort2 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(NormalizedShort2 other) - { - return this.PackedValue.Equals(other.PackedValue); - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(NormalizedShort2 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override string ToString() { - return this.PackedValue.ToString("X"); + var vector = this.ToVector2(); + return FormattableString.Invariant($"NormalizedShort2({vector.X:#0.##}, {vector.Y:#0.##})"); } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y) + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(Vector2 vector) { - const float MaxPos = 0x7FFF; - const float MinNeg = -MaxPos; + vector *= Max; + vector = Vector2.Clamp(vector, Min, Max); - // Clamp the value between min and max values // Round rather than truncate. - uint word2 = (uint)((int)MathF.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF); - uint word1 = (uint)(((int)MathF.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10); + uint word2 = (uint)((int)MathF.Round(vector.X) & 0xFFFF); + uint word1 = (uint)(((int)MathF.Round(vector.Y) & 0xFFFF) << 0x10); return word2 | word1; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/NormalizedShort4.cs index 25b26fa7f7..6fda84bc2e 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort4.cs @@ -15,29 +15,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct NormalizedShort4 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half the maximum byte value. - /// - private static readonly Vector4 Half = new Vector4(127); - - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public NormalizedShort4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + private static readonly Vector4 Max = new Vector4(0x7FFF); + private static readonly Vector4 Min = Vector4.Negate(Max); /// /// Initializes a new instance of the struct. @@ -47,54 +26,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component. /// The w-component. public NormalizedShort4(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - this.PackedValue = Pack(x, y, z, w); } + /// + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public NormalizedShort4(Vector4 vector) => this.PackedValue = Pack(ref vector); + /// public ulong PackedValue { get; set; } /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(NormalizedShort4 left, NormalizedShort4 right) - { - return left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(NormalizedShort4 left, NormalizedShort4 right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) - { - return !left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { vector *= 2F; @@ -103,7 +74,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector4(); @@ -113,14 +84,11 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { const float MaxVal = 0x7FFF; @@ -133,169 +101,76 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is NormalizedShort4 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is NormalizedShort4 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(NormalizedShort4 other) - { - return this.PackedValue.Equals(other.PackedValue); - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(NormalizedShort4 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override string ToString() { - return this.PackedValue.ToString("X"); + var vector = this.ToVector4(); + return FormattableString.Invariant($"NormalizedShort4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong Pack(float x, float y, float z, float w) + [MethodImpl(InliningOptions.ShortMethod)] + private static ulong Pack(ref Vector4 vector) { - const float MaxPos = 0x7FFF; - const float MinNeg = -MaxPos; + vector *= Max; + vector = Vector4.Clamp(vector, Min, Max); - // Clamp the value between min and max values - ulong word4 = ((ulong)MathF.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x00; - ulong word3 = ((ulong)MathF.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10; - ulong word2 = ((ulong)MathF.Round(z * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x20; - ulong word1 = ((ulong)MathF.Round(w * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x30; + // Round rather than truncate. + ulong word4 = ((ulong)MathF.Round(vector.X) & 0xFFFF) << 0x00; + ulong word3 = ((ulong)MathF.Round(vector.Y) & 0xFFFF) << 0x10; + ulong word2 = ((ulong)MathF.Round(vector.Z) & 0xFFFF) << 0x20; + ulong word1 = ((ulong)MathF.Round(vector.W) & 0xFFFF) << 0x30; return word4 | word3 | word2 | word1; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index b12a2bfa58..f1b40e81f0 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -105,6 +105,60 @@ namespace SixLabors.ImageSharp.PixelFormats } } + /// + /// Performs a bulk conversion of a collection of one pixel format into another. + /// + /// The pixel format. + /// The to the source colors. + /// The to the destination colors. + /// The number of pixels to convert. + internal virtual void To(ReadOnlySpan sourceColors, Span destinationColors, int count) + where TPixel2 : struct, IPixel + { + GuardSpans(sourceColors, nameof(sourceColors), destinationColors, nameof(destinationColors), count); + + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); + + // Gray8 and Gray16 are special implementations of IPixel in that they do not conform to the + // standard RGBA colorspace format and must be converted from RGBA using the special ITU BT709 alogrithm. + // One of the requirements of PackFromScaledVector4/ToScaledVector4 is that it unaware of this and + // packs/unpacks the pixel without and conversion so we employ custom methods do do this. + if (typeof(TPixel2).Equals(typeof(Gray16))) + { + ref Gray16 gray16Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationColors)); + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref gray16Ref, i); + dp.ConvertFromRgbaScaledVector4(sp.ToScaledVector4()); + } + + return; + } + + if (typeof(TPixel2).Equals(typeof(Gray8))) + { + ref Gray8 gray8Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationColors)); + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref gray8Ref, i); + dp.ConvertFromRgbaScaledVector4(sp.ToScaledVector4()); + } + + return; + } + + // Normal converson + ref TPixel2 destRef = ref MemoryMarshal.GetReference(destinationColors); + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref TPixel2 dp = ref Unsafe.Add(ref destRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); + } + } + /// /// Verifies that the given 'source' and 'destination' spans are at least of 'minLength' size. /// Throwing an if the condition is not met. diff --git a/src/ImageSharp/PixelFormats/Rg32.cs b/src/ImageSharp/PixelFormats/Rg32.cs index e5ceeacec2..0831f6524e 100644 --- a/src/ImageSharp/PixelFormats/Rg32.cs +++ b/src/ImageSharp/PixelFormats/Rg32.cs @@ -15,24 +15,23 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct Rg32 : IPixel, IPackedVector { + private static readonly Vector2 Max = new Vector2(ushort.MaxValue); + /// /// Initializes a new instance of the struct. /// /// The x-component /// The y-component public Rg32(float x, float y) + : this(new Vector2(x, y)) { - this.PackedValue = Pack(x, y); } /// /// Initializes a new instance of the struct. /// /// The vector containing the component values. - public Rg32(Vector2 vector) - { - this.PackedValue = Pack(vector.X, vector.Y); - } + public Rg32(Vector2 vector) => this.PackedValue = Pack(vector); /// public uint PackedValue { get; set; } @@ -40,214 +39,119 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rg32 left, Rg32 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rg32 left, Rg32 right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rg32 left, Rg32 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rg32 left, Rg32 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - /// Expands the packed representation into a . - /// The vector components are typically expanded in least to greatest significance order. - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector2 ToVector2() - { - return new Vector2( - (this.PackedValue & 0xFFFF) / 65535F, - ((this.PackedValue >> 16) & 0xFFFF) / 65535F); - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y); + var vector2 = new Vector2(vector.X, vector.Y); + this.PackedValue = Pack(vector2); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToVector2(), 0F, 1F); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToVector2(), 0F, 1F); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + /// Expands the packed representation into a . + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public Vector2 ToVector2() => new Vector2(this.PackedValue & 0xFFFF, (this.PackedValue >> 16) & 0xFFFF) / Max; /// - public override bool Equals(object obj) - { - return obj is Rg32 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Rg32 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rg32 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rg32 other) => this.PackedValue.Equals(other.PackedValue); /// public override string ToString() { - return this.ToVector2().ToString(); + var vector = this.ToVector2(); + return FormattableString.Invariant($"Rg32({vector.X:#0.##}, {vector.Y:#0.##})"); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y) + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(Vector2 vector) { - return (uint)( - ((int)Math.Round(x.Clamp(0, 1) * 65535F) & 0xFFFF) | - (((int)Math.Round(y.Clamp(0, 1) * 65535F) & 0xFFFF) << 16)); + vector = Vector2.Clamp(vector, Vector2.Zero, Vector2.One) * Max; + return (uint)(((int)Math.Round(vector.X) & 0xFFFF) | (((int)Math.Round(vector.Y) & 0xFFFF) << 16)); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() => this.ToVector4() * 255F; } -} +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/Rgb24.cs index 24c311d0d3..a2b896605d 100644 --- a/src/ImageSharp/PixelFormats/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/Rgb24.cs @@ -1,7 +1,6 @@ // 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; @@ -16,7 +15,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// [StructLayout(LayoutKind.Explicit)] - public struct Rgb24 : IPixel + public partial struct Rgb24 : IPixel { /// /// The red component. @@ -36,13 +35,16 @@ namespace SixLabors.ImageSharp.PixelFormats [FieldOffset(2)] public byte B; + private static readonly Vector4 MaxBytes = new Vector4(byte.MaxValue); + private static readonly Vector4 Half = new Vector4(0.5F); + /// /// Initializes a new instance of the struct. /// /// The red component. /// The green component. /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgb24(byte r, byte g, byte b) { this.R = r; @@ -56,48 +58,59 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The instance of to convert. /// An instance of . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static implicit operator Rgb24(ColorSpaces.Rgb color) { - var vector = new Vector4(color.ToVector3(), 1); + var vector = new Vector4(color.ToVector3(), 1F); + Rgb24 rgb = default; rgb.PackFromScaledVector4(vector); return rgb; } + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgb24 left, Rgb24 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgb24 left, Rgb24 right) => !left.Equals(right); + /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgb24 other) - { - return this.R == other.R && this.G == other.G && this.B == other.B; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - public override bool Equals(object obj) - { - return obj is Rgb24 other && this.Equals(other); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); - return HashHelpers.Combine(hash, this.B.GetHashCode()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this = Unsafe.As(ref source); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) { this.R = source.R; @@ -106,8 +119,8 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) { this.R = source.R; this.G = source.G; @@ -115,102 +128,95 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) { - return this.ToVector4(); + this.R = source.R; + this.G = source.G; + this.B = source.B; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) { - Rgba32 rgba = default; - rgba.PackFromVector4(vector); - this.PackFromRgba32(rgba); + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) { - return new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) => dest = this; + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this = source; /// - public void ToRgba32(ref Rgba32 dest) - { - dest.Rgb = this; - dest.A = byte.MaxValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this = source.Rgb; - /// - public void ToArgb32(ref Argb32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, byte.MaxValue); /// - public void ToBgr24(ref Bgr24 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); } /// - public void ToBgra32(ref Bgra32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba64(Rgba64 source) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) - { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - } + public override bool Equals(object obj) => obj is Rgb24 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgb24 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); + return HashHelpers.Combine(hash, this.B.GetHashCode()); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + public override string ToString() => $"Rgb24({this.R}, {this.G}, {this.B})"; - /// - public override string ToString() + /// + /// Packs a into a color. + /// + /// The vector containing the values to pack. + [MethodImpl(InliningOptions.ShortMethod)] + private void Pack(ref Vector4 vector) { - return $"({this.R},{this.G},{this.B})"; + vector *= MaxBytes; + vector += Half; + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + + this.R = (byte)vector.X; + this.G = (byte)vector.Y; + this.B = (byte)vector.Z; } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgb48.cs b/src/ImageSharp/PixelFormats/Rgb48.cs index 2d92b0e4e3..7406fda429 100644 --- a/src/ImageSharp/PixelFormats/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/Rgb48.cs @@ -15,9 +15,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// [StructLayout(LayoutKind.Sequential)] - public struct Rgb48 : IPixel + public partial struct Rgb48 : IPixel { - private const float Max = 65535F; + private const float Max = ushort.MaxValue; /// /// Gets or sets the red component. @@ -48,29 +48,6 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = b; } - /// - /// Initializes a new instance of the struct. - /// - /// The red component. - /// The green component. - /// The blue component. - public Rgb48(float r, float g, float b) - : this() - { - this.R = (ushort)MathF.Round(r.Clamp(0, 1) * Max); - this.G = (ushort)MathF.Round(g.Clamp(0, 1) * Max); - this.B = (ushort)MathF.Round(b.Clamp(0, 1) * Max); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the components values. - public Rgb48(Vector3 vector) - : this(vector.X, vector.Y, vector.Z) - { - } - /// /// Compares two objects for equality. /// @@ -79,13 +56,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rgb48 left, Rgb48 right) - { - return left.R == right.R - && left.G == right.G - && left.B == right.B; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgb48 left, Rgb48 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -95,40 +67,22 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rgb48 left, Rgb48 right) - { - return left.R != right.R - || left.G != right.G - || left.B != right.B; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgb48 left, Rgb48 right) => !left.Equals(right); /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R / Max, this.G / Max, this.B / Max, 1); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; @@ -138,114 +92,103 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R / Max, this.G / Max, this.B / Max, 1F); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) { - this.PackFromVector4(source.ToVector4()); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) { - this.PackFromVector4(source.ToVector4()); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) { - this.PackFromVector4(source.ToVector4()); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this = source.Rgb; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); + ushort rgb = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = 255; + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = 255; + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = 255; + byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R); + byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G); + byte b = ImageMaths.DownScaleFrom16BitTo8Bit(this.B); + return new Rgba32(r, g, b, byte.MaxValue); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this = source; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest = this; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) - { - dest.Rgb = this; - dest.A = ushort.MaxValue; - } - /// - public override bool Equals(object obj) - { - return obj is Rgb48 rgb48 && this.Equals(rgb48); - } + public override bool Equals(object obj) => obj is Rgb48 rgb48 && this.Equals(rgb48); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgb48 other) - { - return this.R == other.R - && this.G == other.G - && this.B == other.B; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgb48 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); /// - public override string ToString() => this.ToVector4().ToString(); + public override string ToString() => $"Rgb48({this.R}, {this.G}, {this.B})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() { return HashHelpers.Combine( diff --git a/src/ImageSharp/PixelFormats/Rgba1010102.cs b/src/ImageSharp/PixelFormats/Rgba1010102.cs index 94fb7a41e6..14265b54e9 100644 --- a/src/ImageSharp/PixelFormats/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/Rgba1010102.cs @@ -16,6 +16,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct Rgba1010102 : IPixel, IPackedVector { + private static readonly Vector4 Multiplier = new Vector4(1023F, 1023F, 1023F, 3F); + /// /// Initializes a new instance of the struct. /// @@ -24,18 +26,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component /// The w-component public Rgba1010102(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - this.PackedValue = Pack(x, y, z, w); } /// /// Initializes a new instance of the struct. /// /// The vector containing the component values. - public Rgba1010102(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + public Rgba1010102(Vector4 vector) => this.PackedValue = Pack(ref vector); /// public uint PackedValue { get; set; } @@ -43,206 +42,119 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rgba1010102 left, Rgba1010102 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgba1010102 left, Rgba1010102 right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rgba1010102 left, Rgba1010102 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgba1010102 left, Rgba1010102 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4( - ((this.PackedValue >> 0) & 0x03FF) / 1023F, - ((this.PackedValue >> 10) & 0x03FF) / 1023F, - ((this.PackedValue >> 20) & 0x03FF) / 1023F, - ((this.PackedValue >> 30) & 0x03) / 3F); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); + return new Vector4( + (this.PackedValue >> 0) & 0x03FF, + (this.PackedValue >> 10) & 0x03FF, + (this.PackedValue >> 20) & 0x03FF, + (this.PackedValue >> 30) & 0x03) / Multiplier; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is Rgba1010102 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Rgba1010102 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgba1010102 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgba1010102 other) => this.PackedValue == other.PackedValue; /// public override string ToString() { - return this.ToVector4().ToString(); + var vector = this.ToVector4(); + return FormattableString.Invariant($"Rgba1010102({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y, float z, float w) + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(ref Vector4 vector) { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Multiplier; + return (uint)( - (((int)Math.Round(x.Clamp(0, 1) * 1023F) & 0x03FF) << 0) | - (((int)Math.Round(y.Clamp(0, 1) * 1023F) & 0x03FF) << 10) | - (((int)Math.Round(z.Clamp(0, 1) * 1023F) & 0x03FF) << 20) | - (((int)Math.Round(w.Clamp(0, 1) * 3F) & 0x03) << 30)); + (((int)Math.Round(vector.X) & 0x03FF) << 0) + | (((int)Math.Round(vector.Y) & 0x03FF) << 10) + | (((int)Math.Round(vector.Z) & 0x03FF) << 20) + | (((int)Math.Round(vector.W) & 0x03) << 30)); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs index 2629ce3f79..13432e58f8 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs @@ -3,7 +3,6 @@ using System; using System.Numerics; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.Memory; @@ -19,100 +18,18 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal partial class PixelOperations : PixelOperations { - /// - /// SIMD optimized bulk implementation of - /// that works only with `count` divisible by . - /// - /// The to the source colors. - /// The to the dstination vectors. - /// The number of pixels to convert. - /// - /// Implementation adapted from: - /// - /// http://stackoverflow.com/a/5362789 - /// - /// TODO: We can replace this implementation in the future using new Vector API-s: - /// - /// https://github.com/dotnet/corefx/issues/15957 - /// - /// - internal static void ToVector4SimdAligned(ReadOnlySpan sourceColors, Span destVectors, int count) - { - if (!Vector.IsHardwareAccelerated) - { - throw new InvalidOperationException( - "Rgba32.PixelOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!"); - } - - DebugGuard.IsTrue( - count % Vector.Count == 0, - nameof(count), - "Argument 'count' should divisible by Vector.Count!"); - - var bVec = new Vector(256.0f / 255.0f); - var magicFloat = new Vector(32768.0f); - var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f - var mask = new Vector(255); - - int unpackedRawCount = count * 4; - - ref uint sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(sourceColors)); - ref UnpackedRGBA destBaseAsUnpacked = ref Unsafe.As(ref MemoryMarshal.GetReference(destVectors)); - ref Vector destBaseAsUInt = ref Unsafe.As>(ref destBaseAsUnpacked); - ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsUnpacked); - - for (int i = 0; i < count; i++) - { - uint sVal = Unsafe.Add(ref sourceBase, i); - ref UnpackedRGBA dst = ref Unsafe.Add(ref destBaseAsUnpacked, i); - - // This call is the bottleneck now: - dst.Load(sVal); - } - - int numOfVectors = unpackedRawCount / Vector.Count; - - for (int i = 0; i < numOfVectors; i++) - { - Vector vi = Unsafe.Add(ref destBaseAsUInt, i); - - vi &= mask; - vi |= magicInt; - - var vf = Vector.AsVectorSingle(vi); - vf = (vf - magicFloat) * bVec; - - Unsafe.Add(ref destBaseAsFloat, i) = vf; - } - } - /// internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) { Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); Guard.MustBeSizedAtLeast(destinationVectors, count, nameof(destinationVectors)); - if (count < 256 || !Vector.IsHardwareAccelerated) - { - // Doesn't worth to bother with SIMD: - base.ToVector4(sourceColors, destinationVectors, count); - return; - } + sourceColors = sourceColors.Slice(0, count); + destinationVectors = destinationVectors.Slice(0, count); - int remainder = count % Vector.Count; - int alignedCount = count - remainder; - - if (alignedCount > 0) - { - ToVector4SimdAligned(sourceColors, destinationVectors, alignedCount); - } - - if (remainder > 0) - { - sourceColors = sourceColors.Slice(alignedCount); - destinationVectors = destinationVectors.Slice(alignedCount); - base.ToVector4(sourceColors, destinationVectors, remainder); - } + SimdUtils.BulkConvertByteToNormalizedFloat( + MemoryMarshal.Cast(sourceColors), + MemoryMarshal.Cast(destinationVectors)); } /// @@ -120,29 +37,12 @@ namespace SixLabors.ImageSharp.PixelFormats { GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); - if (!SimdUtils.IsAvx2CompatibleArchitecture) - { - base.PackFromVector4(sourceVectors, destinationColors, count); - return; - } - - int remainder = count % 2; - int alignedCount = count - remainder; - - if (alignedCount > 0) - { - ReadOnlySpan flatSrc = MemoryMarshal.Cast(sourceVectors.Slice(0, alignedCount)); - Span flatDest = MemoryMarshal.Cast(destinationColors); + sourceVectors = sourceVectors.Slice(0, count); + destinationColors = destinationColors.Slice(0, count); - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(flatSrc, flatDest); - } - - if (remainder > 0) - { - // actually: remainder == 1 - int lastIdx = count - 1; - destinationColors[lastIdx].PackFromVector4(sourceVectors[lastIdx]); - } + SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( + MemoryMarshal.Cast(sourceVectors), + MemoryMarshal.Cast(destinationColors)); } /// @@ -156,46 +56,6 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromVector4(sourceVectors, destinationColors, count); } - - /// - internal override void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); - - sourcePixels.Slice(0, count).CopyTo(dest); - } - - /// - /// Value type to store -s unpacked into multiple -s. - /// - [StructLayout(LayoutKind.Sequential)] - private struct UnpackedRGBA - { - private uint r; - - private uint g; - - private uint b; - - private uint a; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Load(uint p) - { - this.r = p; - this.g = p >> GreenShift; - this.b = p >> BlueShift; - this.a = p >> AlphaShift; - } - } } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index 7349639fdc..415c39c0ed 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -41,34 +41,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// public byte A; - /// - /// The shift count for the red component - /// - private const int RedShift = 0; - - /// - /// The shift count for the green component - /// - private const int GreenShift = 8; - - /// - /// The shift count for the blue component - /// - private const int BlueShift = 16; - - /// - /// The shift count for the alpha component - /// - private const int AlphaShift = 24; - - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half vector value. - /// + private static readonly Vector4 MaxBytes = new Vector4(byte.MaxValue); private static readonly Vector4 Half = new Vector4(0.5F); /// @@ -77,7 +50,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The red component. /// The green component. /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(byte r, byte g, byte b) { this.R = r; @@ -93,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(byte r, byte g, byte b, byte a) { this.R = r; @@ -109,7 +82,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(float r, float g, float b, float a = 1) : this() => this.Pack(r, g, b, a); @@ -119,7 +92,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed vector. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(Vector3 vector) : this() => this.Pack(ref vector); @@ -129,7 +102,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed vector. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(Vector4 vector) : this() => this = PackNew(ref vector); @@ -139,7 +112,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The packed value. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(uint packed) : this() => this.Rgba = packed; @@ -148,10 +121,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// public uint Rgba { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } @@ -160,10 +133,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// public Rgb24 Rgb { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + // If this is changed to ShortMethod then several jpeg encoding tests fail + // on 32 bit Net 4.6.2 and NET 4.7.1 + [MethodImpl(InliningOptions.ColdPath)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } @@ -172,10 +147,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// public Bgr24 Bgr { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => new Bgr24(this.R, this.G, this.B); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set { this.R = value.R; @@ -187,10 +162,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// public uint PackedValue { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => this.Rgba; - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => this.Rgba = value; } @@ -200,10 +175,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The instance of to convert. /// An instance of . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static implicit operator Rgba32(ColorSpaces.Rgb color) { - var vector = new Vector4(color.ToVector3(), 1); + var vector = new Vector4(color.ToVector3(), 1F); + Rgba32 rgba = default; rgba.PackFromScaledVector4(vector); return rgba; @@ -217,8 +193,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rgba32 left, Rgba32 right) => left.Rgba == right.Rgba; + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgba32 left, Rgba32 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -228,8 +204,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rgba32 left, Rgba32 right) => left.Rgba != right.Rgba; + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgba32 left, Rgba32 right) => !left.Equals(right); /// /// Creates a new instance of the struct. @@ -247,11 +223,23 @@ namespace SixLabors.ImageSharp.PixelFormats public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) => this = source; + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + + /// + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) { this.R = source.R; @@ -261,7 +249,15 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) + { + this.Bgr = source; + this.A = byte.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) { this.R = source.R; @@ -270,148 +266,93 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = source.A; } - /// - /// Converts the value of this instance to a hexadecimal string. - /// - /// A hexadecimal string representation of the value. - public string ToHex() - { - uint hexOrder = (uint)(this.A << 0 | this.B << 8 | this.G << 16 | this.R << 24); - return hexOrder.ToString("X8"); - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) => dest = Unsafe.As(ref this); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) => dest = this; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; + this.A = byte.MaxValue; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; + this.Rgb = source; + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() => this.ToVector4(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; - - /// - /// Gets the value of this struct as . - /// Useful for changing the component order. - /// - /// A value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Bgra32 ToBgra32() => new Bgra32(this.R, this.G, this.B, this.A); - - /// - /// Gets the value of this struct as . - /// Useful for changing the component order. - /// - /// A value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Argb32 ToArgb32() => new Argb32(this.R, this.G, this.B, this.A); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this = source; - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32 ToRgba32() => this; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) { - // Taken from libpng pngtran.c line: 2419 - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - this.A = (byte)(((source.A * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); + this.A = ImageMaths.DownScaleFrom16BitTo8Bit(source.A); } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + /// Converts the value of this instance to a hexadecimal string. + /// + /// A hexadecimal string representation of the value. + public string ToHex() + { + uint hexOrder = (uint)(this.A << 0 | this.B << 8 | this.G << 16 | this.R << 24); + return hexOrder.ToString("X8"); + } /// public override bool Equals(object obj) => obj is Rgba32 rgba32 && this.Equals(rgba32); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgba32 other) => this.Rgba == other.Rgba; + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgba32 other) => this.Rgba.Equals(other.Rgba); /// - public override string ToString() => $"({this.R},{this.G},{this.B},{this.A})"; + public override string ToString() => $"Rgba32({this.R}, {this.G}, {this.B}, {this.A})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.Rgba.GetHashCode(); - /// - /// Gets the representation without normalizing to [0, 1] - /// - /// A of values in [0, 255] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Vector4 ToByteScaledVector4() => new Vector4(this.R, this.G, this.B, this.A); - /// /// Packs a into a color returning a new instance as a result. /// /// The vector containing the values to pack. /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static Rgba32 PackNew(ref Vector4 vector) { vector *= MaxBytes; @@ -428,7 +369,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The y-component /// The z-component /// The w-component - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(float x, float y, float z, float w) { var value = new Vector4(x, y, z, w); @@ -439,10 +380,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs a into a uint. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector3 vector) { - var value = new Vector4(vector, 1); + var value = new Vector4(vector, 1F); this.Pack(ref value); } @@ -450,7 +391,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector4 vector) { vector *= MaxBytes; diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index 8e6be1e8c4..738c5e3dd8 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -15,9 +15,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// [StructLayout(LayoutKind.Sequential)] - public struct Rgba64 : IPixel, IPackedVector + public partial struct Rgba64 : IPixel, IPackedVector { - private const float Max = 65535F; + private const float Max = ushort.MaxValue; /// /// Gets or sets the red component. @@ -47,7 +47,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// The blue component. /// The alpha component. public Rgba64(ushort r, ushort g, ushort b, ushort a) - : this() { this.R = r; this.G = g; @@ -55,126 +54,63 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = a; } - /// - /// Initializes a new instance of the struct. - /// - /// The red component. - /// The green component. - /// The blue component. - /// The alpha component. - public Rgba64(float r, float g, float b, float a) - : this() - { - this.R = (ushort)MathF.Round(r.Clamp(0, 1) * Max); - this.G = (ushort)MathF.Round(g.Clamp(0, 1) * Max); - this.B = (ushort)MathF.Round(b.Clamp(0, 1) * Max); - this.A = (ushort)MathF.Round(a.Clamp(0, 1) * Max); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the components values. - public Rgba64(Vector4 vector) - : this(vector.X, vector.Y, vector.Z, vector.W) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The packed value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba64(ulong packed) - : this() - { - this.PackedValue = packed; - } - /// /// Gets or sets the RGB components of this struct as /// public Rgb48 Rgb { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } /// public ulong PackedValue { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rgba64 left, Rgba64 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgba64 left, Rgba64 right) => left.PackedValue == right.PackedValue; /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rgba64 left, Rgba64 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgba64 left, Rgba64 right) => left.PackedValue != right.PackedValue; /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R, this.G, this.B, this.A) / Max; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; @@ -185,116 +121,115 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / Max; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) { - this.PackFromVector4(source.ToVector4()); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) { - this.PackFromVector4(source.ToVector4()); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ushort.MaxValue; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this = source; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) { - // Taken from libpng pngtran.c line: 2419 - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = (byte)(((this.A * 255) + 32895) >> 16); + ushort rgb = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; + this.A = ushort.MaxValue; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) { - this.Rgb = source; + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; this.A = ushort.MaxValue; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest = this.Rgb; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest = this; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = (byte)(((this.A * 255) + 32895) >> 16); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ushort.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = (byte)(((this.A * 255) + 32895) >> 16); + byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R); + byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G); + byte b = ImageMaths.DownScaleFrom16BitTo8Bit(this.B); + byte a = ImageMaths.DownScaleFrom16BitTo8Bit(this.A); + return new Rgba32(r, g, b, a); } - /// - public override bool Equals(object obj) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) { - return obj is Rgba64 rgba64 && this.Equals(rgba64); + this.Rgb = source; + this.A = ushort.MaxValue; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba64(Rgba64 source) => this = source; + /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgba64 other) - { - return this.PackedValue == other.PackedValue; - } + public override bool Equals(object obj) => obj is Rgba64 rgba64 && this.Equals(rgba64); /// - public override string ToString() - { - return $"({this.R},{this.G},{this.B},{this.A})"; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgba64 other) => this.PackedValue.Equals(other.PackedValue); + + /// + public override string ToString() => $"Rgba64({this.R}, {this.G}, {this.B}, {this.A})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/RgbaVector.Definitions.cs b/src/ImageSharp/PixelFormats/RgbaVector.Definitions.cs deleted file mode 100644 index 2ef37c43ae..0000000000 --- a/src/ImageSharp/PixelFormats/RgbaVector.Definitions.cs +++ /dev/null @@ -1,721 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Provides operators and composition algorithms. - /// - public partial struct RgbaVector - { - /// - /// Represents a matching the W3C definition that has an hex value of #F0F8FF. - /// - public static readonly RgbaVector AliceBlue = NamedColors.AliceBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #FAEBD7. - /// - public static readonly RgbaVector AntiqueWhite = NamedColors.AntiqueWhite; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FFFF. - /// - public static readonly RgbaVector Aqua = NamedColors.Aqua; - - /// - /// Represents a matching the W3C definition that has an hex value of #7FFFD4. - /// - public static readonly RgbaVector Aquamarine = NamedColors.Aquamarine; - - /// - /// Represents a matching the W3C definition that has an hex value of #F0FFFF. - /// - public static readonly RgbaVector Azure = NamedColors.Azure; - - /// - /// Represents a matching the W3C definition that has an hex value of #F5F5DC. - /// - public static readonly RgbaVector Beige = NamedColors.Beige; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFE4C4. - /// - public static readonly RgbaVector Bisque = NamedColors.Bisque; - - /// - /// Represents a matching the W3C definition that has an hex value of #000000. - /// - public static readonly RgbaVector Black = NamedColors.Black; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFEBCD. - /// - public static readonly RgbaVector BlanchedAlmond = NamedColors.BlanchedAlmond; - - /// - /// Represents a matching the W3C definition that has an hex value of #0000FF. - /// - public static readonly RgbaVector Blue = NamedColors.Blue; - - /// - /// Represents a matching the W3C definition that has an hex value of #8A2BE2. - /// - public static readonly RgbaVector BlueViolet = NamedColors.BlueViolet; - - /// - /// Represents a matching the W3C definition that has an hex value of #A52A2A. - /// - public static readonly RgbaVector Brown = NamedColors.Brown; - - /// - /// Represents a matching the W3C definition that has an hex value of #DEB887. - /// - public static readonly RgbaVector BurlyWood = NamedColors.BurlyWood; - - /// - /// Represents a matching the W3C definition that has an hex value of #5F9EA0. - /// - public static readonly RgbaVector CadetBlue = NamedColors.CadetBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #7FFF00. - /// - public static readonly RgbaVector Chartreuse = NamedColors.Chartreuse; - - /// - /// Represents a matching the W3C definition that has an hex value of #D2691E. - /// - public static readonly RgbaVector Chocolate = NamedColors.Chocolate; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF7F50. - /// - public static readonly RgbaVector Coral = NamedColors.Coral; - - /// - /// Represents a matching the W3C definition that has an hex value of #6495ED. - /// - public static readonly RgbaVector CornflowerBlue = NamedColors.CornflowerBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFF8DC. - /// - public static readonly RgbaVector Cornsilk = NamedColors.Cornsilk; - - /// - /// Represents a matching the W3C definition that has an hex value of #DC143C. - /// - public static readonly RgbaVector Crimson = NamedColors.Crimson; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FFFF. - /// - public static readonly RgbaVector Cyan = NamedColors.Cyan; - - /// - /// Represents a matching the W3C definition that has an hex value of #00008B. - /// - public static readonly RgbaVector DarkBlue = NamedColors.DarkBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #008B8B. - /// - public static readonly RgbaVector DarkCyan = NamedColors.DarkCyan; - - /// - /// Represents a matching the W3C definition that has an hex value of #B8860B. - /// - public static readonly RgbaVector DarkGoldenrod = NamedColors.DarkGoldenrod; - - /// - /// Represents a matching the W3C definition that has an hex value of #A9A9A9. - /// - public static readonly RgbaVector DarkGray = NamedColors.DarkGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #006400. - /// - public static readonly RgbaVector DarkGreen = NamedColors.DarkGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #BDB76B. - /// - public static readonly RgbaVector DarkKhaki = NamedColors.DarkKhaki; - - /// - /// Represents a matching the W3C definition that has an hex value of #8B008B. - /// - public static readonly RgbaVector DarkMagenta = NamedColors.DarkMagenta; - - /// - /// Represents a matching the W3C definition that has an hex value of #556B2F. - /// - public static readonly RgbaVector DarkOliveGreen = NamedColors.DarkOliveGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF8C00. - /// - public static readonly RgbaVector DarkOrange = NamedColors.DarkOrange; - - /// - /// Represents a matching the W3C definition that has an hex value of #9932CC. - /// - public static readonly RgbaVector DarkOrchid = NamedColors.DarkOrchid; - - /// - /// Represents a matching the W3C definition that has an hex value of #8B0000. - /// - public static readonly RgbaVector DarkRed = NamedColors.DarkRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #E9967A. - /// - public static readonly RgbaVector DarkSalmon = NamedColors.DarkSalmon; - - /// - /// Represents a matching the W3C definition that has an hex value of #8FBC8B. - /// - public static readonly RgbaVector DarkSeaGreen = NamedColors.DarkSeaGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #483D8B. - /// - public static readonly RgbaVector DarkSlateBlue = NamedColors.DarkSlateBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #2F4F4F. - /// - public static readonly RgbaVector DarkSlateGray = NamedColors.DarkSlateGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #00CED1. - /// - public static readonly RgbaVector DarkTurquoise = NamedColors.DarkTurquoise; - - /// - /// Represents a matching the W3C definition that has an hex value of #9400D3. - /// - public static readonly RgbaVector DarkViolet = NamedColors.DarkViolet; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF1493. - /// - public static readonly RgbaVector DeepPink = NamedColors.DeepPink; - - /// - /// Represents a matching the W3C definition that has an hex value of #00BFFF. - /// - public static readonly RgbaVector DeepSkyBlue = NamedColors.DeepSkyBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #696969. - /// - public static readonly RgbaVector DimGray = NamedColors.DimGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #1E90FF. - /// - public static readonly RgbaVector DodgerBlue = NamedColors.DodgerBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #B22222. - /// - public static readonly RgbaVector Firebrick = NamedColors.Firebrick; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFAF0. - /// - public static readonly RgbaVector FloralWhite = NamedColors.FloralWhite; - - /// - /// Represents a matching the W3C definition that has an hex value of #228B22. - /// - public static readonly RgbaVector ForestGreen = NamedColors.ForestGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF00FF. - /// - public static readonly RgbaVector Fuchsia = NamedColors.Fuchsia; - - /// - /// Represents a matching the W3C definition that has an hex value of #DCDCDC. - /// - public static readonly RgbaVector Gainsboro = NamedColors.Gainsboro; - - /// - /// Represents a matching the W3C definition that has an hex value of #F8F8FF. - /// - public static readonly RgbaVector GhostWhite = NamedColors.GhostWhite; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFD700. - /// - public static readonly RgbaVector Gold = NamedColors.Gold; - - /// - /// Represents a matching the W3C definition that has an hex value of #DAA520. - /// - public static readonly RgbaVector Goldenrod = NamedColors.Goldenrod; - - /// - /// Represents a matching the W3C definition that has an hex value of #808080. - /// - public static readonly RgbaVector Gray = NamedColors.Gray; - - /// - /// Represents a matching the W3C definition that has an hex value of #008000. - /// - public static readonly RgbaVector Green = NamedColors.Green; - - /// - /// Represents a matching the W3C definition that has an hex value of #ADFF2F. - /// - public static readonly RgbaVector GreenYellow = NamedColors.GreenYellow; - - /// - /// Represents a matching the W3C definition that has an hex value of #F0FFF0. - /// - public static readonly RgbaVector Honeydew = NamedColors.Honeydew; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF69B4. - /// - public static readonly RgbaVector HotPink = NamedColors.HotPink; - - /// - /// Represents a matching the W3C definition that has an hex value of #CD5C5C. - /// - public static readonly RgbaVector IndianRed = NamedColors.IndianRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #4B0082. - /// - public static readonly RgbaVector Indigo = NamedColors.Indigo; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFFF0. - /// - public static readonly RgbaVector Ivory = NamedColors.Ivory; - - /// - /// Represents a matching the W3C definition that has an hex value of #F0E68C. - /// - public static readonly RgbaVector Khaki = NamedColors.Khaki; - - /// - /// Represents a matching the W3C definition that has an hex value of #E6E6FA. - /// - public static readonly RgbaVector Lavender = NamedColors.Lavender; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFF0F5. - /// - public static readonly RgbaVector LavenderBlush = NamedColors.LavenderBlush; - - /// - /// Represents a matching the W3C definition that has an hex value of #7CFC00. - /// - public static readonly RgbaVector LawnGreen = NamedColors.LawnGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFACD. - /// - public static readonly RgbaVector LemonChiffon = NamedColors.LemonChiffon; - - /// - /// Represents a matching the W3C definition that has an hex value of #ADD8E6. - /// - public static readonly RgbaVector LightBlue = NamedColors.LightBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #F08080. - /// - public static readonly RgbaVector LightCoral = NamedColors.LightCoral; - - /// - /// Represents a matching the W3C definition that has an hex value of #E0FFFF. - /// - public static readonly RgbaVector LightCyan = NamedColors.LightCyan; - - /// - /// Represents a matching the W3C definition that has an hex value of #FAFAD2. - /// - public static readonly RgbaVector LightGoldenrodYellow = NamedColors.LightGoldenrodYellow; - - /// - /// Represents a matching the W3C definition that has an hex value of #D3D3D3. - /// - public static readonly RgbaVector LightGray = NamedColors.LightGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #90EE90. - /// - public static readonly RgbaVector LightGreen = NamedColors.LightGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFB6C1. - /// - public static readonly RgbaVector LightPink = NamedColors.LightPink; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFA07A. - /// - public static readonly RgbaVector LightSalmon = NamedColors.LightSalmon; - - /// - /// Represents a matching the W3C definition that has an hex value of #20B2AA. - /// - public static readonly RgbaVector LightSeaGreen = NamedColors.LightSeaGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #87CEFA. - /// - public static readonly RgbaVector LightSkyBlue = NamedColors.LightSkyBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #778899. - /// - public static readonly RgbaVector LightSlateGray = NamedColors.LightSlateGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #B0C4DE. - /// - public static readonly RgbaVector LightSteelBlue = NamedColors.LightSteelBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFFE0. - /// - public static readonly RgbaVector LightYellow = NamedColors.LightYellow; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FF00. - /// - public static readonly RgbaVector Lime = NamedColors.Lime; - - /// - /// Represents a matching the W3C definition that has an hex value of #32CD32. - /// - public static readonly RgbaVector LimeGreen = NamedColors.LimeGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FAF0E6. - /// - public static readonly RgbaVector Linen = NamedColors.Linen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF00FF. - /// - public static readonly RgbaVector Magenta = NamedColors.Magenta; - - /// - /// Represents a matching the W3C definition that has an hex value of #800000. - /// - public static readonly RgbaVector Maroon = NamedColors.Maroon; - - /// - /// Represents a matching the W3C definition that has an hex value of #66CDAA. - /// - public static readonly RgbaVector MediumAquamarine = NamedColors.MediumAquamarine; - - /// - /// Represents a matching the W3C definition that has an hex value of #0000CD. - /// - public static readonly RgbaVector MediumBlue = NamedColors.MediumBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #BA55D3. - /// - public static readonly RgbaVector MediumOrchid = NamedColors.MediumOrchid; - - /// - /// Represents a matching the W3C definition that has an hex value of #9370DB. - /// - public static readonly RgbaVector MediumPurple = NamedColors.MediumPurple; - - /// - /// Represents a matching the W3C definition that has an hex value of #3CB371. - /// - public static readonly RgbaVector MediumSeaGreen = NamedColors.MediumSeaGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #7B68EE. - /// - public static readonly RgbaVector MediumSlateBlue = NamedColors.MediumSlateBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FA9A. - /// - public static readonly RgbaVector MediumSpringGreen = NamedColors.MediumSpringGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #48D1CC. - /// - public static readonly RgbaVector MediumTurquoise = NamedColors.MediumTurquoise; - - /// - /// Represents a matching the W3C definition that has an hex value of #C71585. - /// - public static readonly RgbaVector MediumVioletRed = NamedColors.MediumVioletRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #191970. - /// - public static readonly RgbaVector MidnightBlue = NamedColors.MidnightBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #F5FFFA. - /// - public static readonly RgbaVector MintCream = NamedColors.MintCream; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFE4E1. - /// - public static readonly RgbaVector MistyRose = NamedColors.MistyRose; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFE4B5. - /// - public static readonly RgbaVector Moccasin = NamedColors.Moccasin; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFDEAD. - /// - public static readonly RgbaVector NavajoWhite = NamedColors.NavajoWhite; - - /// - /// Represents a matching the W3C definition that has an hex value of #000080. - /// - public static readonly RgbaVector Navy = NamedColors.Navy; - - /// - /// Represents a matching the W3C definition that has an hex value of #FDF5E6. - /// - public static readonly RgbaVector OldLace = NamedColors.OldLace; - - /// - /// Represents a matching the W3C definition that has an hex value of #808000. - /// - public static readonly RgbaVector Olive = NamedColors.Olive; - - /// - /// Represents a matching the W3C definition that has an hex value of #6B8E23. - /// - public static readonly RgbaVector OliveDrab = NamedColors.OliveDrab; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFA500. - /// - public static readonly RgbaVector Orange = NamedColors.Orange; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF4500. - /// - public static readonly RgbaVector OrangeRed = NamedColors.OrangeRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #DA70D6. - /// - public static readonly RgbaVector Orchid = NamedColors.Orchid; - - /// - /// Represents a matching the W3C definition that has an hex value of #EEE8AA. - /// - public static readonly RgbaVector PaleGoldenrod = NamedColors.PaleGoldenrod; - - /// - /// Represents a matching the W3C definition that has an hex value of #98FB98. - /// - public static readonly RgbaVector PaleGreen = NamedColors.PaleGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #AFEEEE. - /// - public static readonly RgbaVector PaleTurquoise = NamedColors.PaleTurquoise; - - /// - /// Represents a matching the W3C definition that has an hex value of #DB7093. - /// - public static readonly RgbaVector PaleVioletRed = NamedColors.PaleVioletRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFEFD5. - /// - public static readonly RgbaVector PapayaWhip = NamedColors.PapayaWhip; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFDAB9. - /// - public static readonly RgbaVector PeachPuff = NamedColors.PeachPuff; - - /// - /// Represents a matching the W3C definition that has an hex value of #CD853F. - /// - public static readonly RgbaVector Peru = NamedColors.Peru; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFC0CB. - /// - public static readonly RgbaVector Pink = NamedColors.Pink; - - /// - /// Represents a matching the W3C definition that has an hex value of #DDA0DD. - /// - public static readonly RgbaVector Plum = NamedColors.Plum; - - /// - /// Represents a matching the W3C definition that has an hex value of #B0E0E6. - /// - public static readonly RgbaVector PowderBlue = NamedColors.PowderBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #800080. - /// - public static readonly RgbaVector Purple = NamedColors.Purple; - - /// - /// Represents a matching the W3C definition that has an hex value of #663399. - /// - public static readonly RgbaVector RebeccaPurple = NamedColors.RebeccaPurple; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF0000. - /// - public static readonly RgbaVector Red = NamedColors.Red; - - /// - /// Represents a matching the W3C definition that has an hex value of #BC8F8F. - /// - public static readonly RgbaVector RosyBrown = NamedColors.RosyBrown; - - /// - /// Represents a matching the W3C definition that has an hex value of #4169E1. - /// - public static readonly RgbaVector RoyalBlue = NamedColors.RoyalBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #8B4513. - /// - public static readonly RgbaVector SaddleBrown = NamedColors.SaddleBrown; - - /// - /// Represents a matching the W3C definition that has an hex value of #FA8072. - /// - public static readonly RgbaVector Salmon = NamedColors.Salmon; - - /// - /// Represents a matching the W3C definition that has an hex value of #F4A460. - /// - public static readonly RgbaVector SandyBrown = NamedColors.SandyBrown; - - /// - /// Represents a matching the W3C definition that has an hex value of #2E8B57. - /// - public static readonly RgbaVector SeaGreen = NamedColors.SeaGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFF5EE. - /// - public static readonly RgbaVector SeaShell = NamedColors.SeaShell; - - /// - /// Represents a matching the W3C definition that has an hex value of #A0522D. - /// - public static readonly RgbaVector Sienna = NamedColors.Sienna; - - /// - /// Represents a matching the W3C definition that has an hex value of #C0C0C0. - /// - public static readonly RgbaVector Silver = NamedColors.Silver; - - /// - /// Represents a matching the W3C definition that has an hex value of #87CEEB. - /// - public static readonly RgbaVector SkyBlue = NamedColors.SkyBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #6A5ACD. - /// - public static readonly RgbaVector SlateBlue = NamedColors.SlateBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #708090. - /// - public static readonly RgbaVector SlateGray = NamedColors.SlateGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFAFA. - /// - public static readonly RgbaVector Snow = NamedColors.Snow; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FF7F. - /// - public static readonly RgbaVector SpringGreen = NamedColors.SpringGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #4682B4. - /// - public static readonly RgbaVector SteelBlue = NamedColors.SteelBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #D2B48C. - /// - public static readonly RgbaVector Tan = NamedColors.Tan; - - /// - /// Represents a matching the W3C definition that has an hex value of #008080. - /// - public static readonly RgbaVector Teal = NamedColors.Teal; - - /// - /// Represents a matching the W3C definition that has an hex value of #D8BFD8. - /// - public static readonly RgbaVector Thistle = NamedColors.Thistle; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF6347. - /// - public static readonly RgbaVector Tomato = NamedColors.Tomato; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFFFF. - /// - public static readonly RgbaVector Transparent = NamedColors.Transparent; - - /// - /// Represents a matching the W3C definition that has an hex value of #40E0D0. - /// - public static readonly RgbaVector Turquoise = NamedColors.Turquoise; - - /// - /// Represents a matching the W3C definition that has an hex value of #EE82EE. - /// - public static readonly RgbaVector Violet = NamedColors.Violet; - - /// - /// Represents a matching the W3C definition that has an hex value of #F5DEB3. - /// - public static readonly RgbaVector Wheat = NamedColors.Wheat; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFFFF. - /// - public static readonly RgbaVector White = NamedColors.White; - - /// - /// Represents a matching the W3C definition that has an hex value of #F5F5F5. - /// - public static readonly RgbaVector WhiteSmoke = NamedColors.WhiteSmoke; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFF00. - /// - public static readonly RgbaVector Yellow = NamedColors.Yellow; - - /// - /// Represents a matching the W3C definition that has an hex value of #9ACD32. - /// - public static readonly RgbaVector YellowGreen = NamedColors.YellowGreen; - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs index ce40665cd4..aae6ee6940 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs @@ -18,11 +18,23 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override unsafe void ToVector4(ReadOnlySpan sourceColors, Span destVectors, int count) + internal override void PackFromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { - GuardSpans(sourceColors, nameof(sourceColors), destVectors, nameof(destVectors), count); + GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); - MemoryMarshal.Cast(sourceColors).Slice(0, count).CopyTo(destVectors); + MemoryMarshal.Cast(sourceVectors).Slice(0, count).CopyTo(destinationColors); + } + + /// + internal override void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) + => this.ToVector4(sourceColors, destinationVectors, count); + + /// + internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) + { + GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count); + + MemoryMarshal.Cast(sourceColors).Slice(0, count).CopyTo(destinationVectors); } } } diff --git a/src/ImageSharp/PixelFormats/RgbaVector.cs b/src/ImageSharp/PixelFormats/RgbaVector.cs index dd5f77b80f..b2a3dc578e 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.PixelFormats { @@ -18,36 +19,32 @@ namespace SixLabors.ImageSharp.PixelFormats /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, /// as it avoids the need to create new values for modification operations. /// + [StructLayout(LayoutKind.Sequential)] public partial struct RgbaVector : IPixel { /// - /// The maximum byte value. + /// Gets or sets the red component. /// - private static readonly Vector4 MaxBytes = new Vector4(255); + public float R; /// - /// The half vector value. + /// Gets or sets the green component. /// - private static readonly Vector4 Half = new Vector4(0.5F); + public float G; /// - /// The backing vector for SIMD support. + /// Gets or sets the blue component. /// - private Vector4 backingVector; + public float B; /// - /// Initializes a new instance of the struct. + /// Gets or sets the alpha component. /// - /// The red component. - /// The green component. - /// The blue component. - /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public RgbaVector(byte r, byte g, byte b, byte a = 255) - : this() - { - this.backingVector = new Vector4(r, g, b, a) / MaxBytes; - } + public float A; + + private const float MaxBytes = byte.MaxValue; + private static readonly Vector4 Max = new Vector4(MaxBytes); + private static readonly Vector4 Half = new Vector4(0.5F); /// /// Initializes a new instance of the struct. @@ -56,128 +53,25 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public RgbaVector(float r, float g, float b, float a = 1) - : this() - { - this.backingVector = new Vector4(r, g, b, a); - } - - /// - /// Initializes a new instance of the struct. - /// - /// - /// The vector containing the components for the packed vector. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public RgbaVector(Vector3 vector) - : this() - { - this.backingVector = new Vector4(vector, 1); - } - - /// - /// Initializes a new instance of the struct. - /// - /// - /// The vector containing the components for the packed vector. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public RgbaVector(Vector4 vector) - : this() - { - this.backingVector = vector; - } - - /// - /// Gets or sets the red component. - /// - public float R { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.backingVector.X; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.backingVector.X = value; - } - } - - /// - /// Gets or sets the green component. - /// - public float G - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.backingVector.Y; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.backingVector.Y = value; - } - } - - /// - /// Gets or sets the blue component. - /// - public float B - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.backingVector.Z; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.backingVector.Z = value; - } - } - - /// - /// Gets or sets the alpha component. - /// - public float A - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.backingVector.W; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.backingVector.W = value; - } + this.R = r; + this.G = g; + this.B = b; + this.A = a; } /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(RgbaVector left, RgbaVector right) - { - return left.backingVector == right.backingVector; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(RgbaVector left, RgbaVector right) => left.Equals(right); /// /// Compares two objects for equality. @@ -187,11 +81,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(RgbaVector left, RgbaVector right) - { - return left.backingVector != right.backingVector; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(RgbaVector left, RgbaVector right) => !left.Equals(right); /// /// Creates a new instance of the struct. @@ -203,174 +94,111 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The . /// - public static RgbaVector FromHex(string hex) - { - return ColorBuilder.FromHex(hex); - } + public static RgbaVector FromHex(string hex) => ColorBuilder.FromHex(hex); /// - public PixelOperations CreatePixelOperations() => new RgbaVector.PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.backingVector = source.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.backingVector = source.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) { - this.backingVector = source.ToVector4(); + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); + this.R = vector.X; + this.G = vector.Y; + this.B = vector.Z; + this.A = vector.W; } - /// - /// Converts the value of this instance to a hexadecimal string. - /// - /// A hexadecimal string representation of the value. - public string ToHex() - { - // Hex is RRGGBBAA - Vector4 vector = this.backingVector * MaxBytes; - vector += Half; - uint hexOrder = (uint)((byte)vector.W | (byte)vector.Z << 8 | (byte)vector.Y << 16 | (byte)vector.X << 24); - return hexOrder.ToString("X8"); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) + /// + /// Converts the value of this instance to a hexadecimal string. + /// + /// A hexadecimal string representation of the value. + public string ToHex() { - this.backingVector = vector; + // Hex is RRGGBBAA + Vector4 vector = this.ToVector4() * Max; + vector += Half; + uint hexOrder = (uint)((byte)vector.W | (byte)vector.Z << 8 | (byte)vector.Y << 16 | (byte)vector.X << 24); + return hexOrder.ToString("X8"); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return this.backingVector; - } + public override bool Equals(object obj) => obj is RgbaVector other && this.Equals(other); /// - public override bool Equals(object obj) - { - return obj is RgbaVector other && this.Equals(other); - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(RgbaVector other) => + this.R.Equals(other.R) + && this.G.Equals(other.G) + && this.B.Equals(other.B) + && this.A.Equals(other.A); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(RgbaVector other) - { - return this.backingVector == other.backingVector; - } - - /// - /// Gets a string representation of the packed vector. - /// - /// A string representation of the packed vector. public override string ToString() { - return this.ToVector4().ToString(); + var vector = this.ToVector4(); + return FormattableString.Invariant($"RgbaVector({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##}, {this.A:#0.##})"); } /// public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); + hash = HashHelpers.Combine(hash, this.B.GetHashCode()); + return HashHelpers.Combine(hash, this.A.GetHashCode()); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() => Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes; } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/Short2.cs index 9fc7618b91..81df3ef7b9 100644 --- a/src/ImageSharp/PixelFormats/Short2.cs +++ b/src/ImageSharp/PixelFormats/Short2.cs @@ -15,39 +15,30 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct Short2 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector2 MaxBytes = new Vector2(255); + // Largest two byte positive number 0xFFFF >> 1; + private const float MaxPos = 0x7FFF; - /// - /// The half the maximum byte value. - /// - private static readonly Vector2 Half = new Vector2(127); + // Two's complement + private const float MinNeg = ~(int)MaxPos; - /// - /// The vector value used for rounding. - /// - private static readonly Vector2 Round = new Vector2(.5F); + private static readonly Vector2 Max = new Vector2(MaxPos); + private static readonly Vector2 Min = new Vector2(MinNeg); /// /// Initializes a new instance of the struct. /// - /// The vector containing the component values. - public Short2(Vector2 vector) + /// The x-component. + /// The y-component. + public Short2(float x, float y) + : this(new Vector2(x, y)) { - this.PackedValue = Pack(vector.X, vector.Y); } /// /// Initializes a new instance of the struct. /// - /// The x-component. - /// The y-component. - public Short2(float x, float y) - { - this.PackedValue = Pack(x, y); - } + /// The vector containing the component values. + public Short2(Vector2 vector) => this.PackedValue = Pack(vector); /// public uint PackedValue { get; set; } @@ -55,53 +46,39 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// - /// True if the parameter is equal to the parameter; otherwise, false. + /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Short2 left, Short2 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Short2 left, Short2 right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Short2 left, Short2 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Short2 left, Short2 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 65534F; scaled -= new Vector2(32767F); - this.PackedValue = Pack(scaled.X, scaled.Y); + this.PackedValue = Pack(scaled); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector2(); @@ -111,182 +88,91 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y); + var vector2 = new Vector2(vector.X, vector.Y); + this.PackedValue = Pack(vector2); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10), 0, 1); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10), 0, 1); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector2 vector = new Vector2(source.R, source.G) / 255; - vector *= 65534; - vector -= new Vector2(32767); - this.PackedValue = Pack(vector.X, vector.Y); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector2 vector = new Vector2(source.R, source.G) / 255; - vector *= 65534; - vector -= new Vector2(32767); - this.PackedValue = Pack(vector.X, vector.Y); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector2 vector = new Vector2(source.R, source.G) / 255; - vector *= 65534; - vector -= new Vector2(32767); - this.PackedValue = Pack(vector.X, vector.Y); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. /// /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector2 ToVector2() - { - return new Vector2((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10)); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector2 ToVector2() => new Vector2((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10)); /// - public override bool Equals(object obj) - { - return obj is Short2 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Short2 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Short2 other) - { - return this == other; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Short2 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override string ToString() { - return this.PackedValue.ToString("x8"); + var vector = this.ToVector2(); + return FormattableString.Invariant($"Short2({vector.X:#0.##}, {vector.Y:#0.##})"); } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y) + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(Vector2 vector) { - // Largest two byte positive number 0xFFFF >> 1; - const float MaxPos = 0x7FFF; - const float MinNeg = ~(int)MaxPos; - - // Clamp the value between min and max values - uint word2 = (uint)Math.Round(x.Clamp(MinNeg, MaxPos)) & 0xFFFF; - uint word1 = ((uint)Math.Round(y.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x10; + vector = Vector2.Clamp(vector, Min, Max); + uint word2 = (uint)Math.Round(vector.X) & 0xFFFF; + uint word1 = ((uint)Math.Round(vector.Y) & 0xFFFF) << 0x10; return word2 | word1; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector2 ToByteScaledVector2() - { - var vector = this.ToVector2(); - vector /= 65534; - vector *= 255; - vector += Half; - vector += Round; - vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes); - return vector; - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/Short4.cs index 641f154f94..48bd01d6e1 100644 --- a/src/ImageSharp/PixelFormats/Short4.cs +++ b/src/ImageSharp/PixelFormats/Short4.cs @@ -15,29 +15,14 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct Short4 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half the maximum byte value. - /// - private static readonly Vector4 Half = new Vector4(127); + // Largest two byte positive number 0xFFFF >> 1; + private const float MaxPos = 0x7FFF; - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); + // Two's complement + private const float MinNeg = ~(int)MaxPos; - /// - /// Initializes a new instance of the struct. - /// - /// A vector containing the initial values for the components. - public Short4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + private static readonly Vector4 Max = new Vector4(MaxPos); + private static readonly Vector4 Min = new Vector4(MinNeg); /// /// Initializes a new instance of the struct. @@ -47,54 +32,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component. /// The w-component. public Short4(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - this.PackedValue = Pack(x, y, z, w); } + /// + /// Initializes a new instance of the struct. + /// + /// A vector containing the initial values for the components. + public Short4(Vector4 vector) => this.PackedValue = Pack(ref vector); + /// public ulong PackedValue { get; set; } /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Short4 left, Short4 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Short4 left, Short4 right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Short4 left, Short4 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Short4 left, Short4 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { vector *= 65534F; @@ -103,7 +80,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector4(); @@ -113,14 +90,11 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { return new Vector4( @@ -131,168 +105,78 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - var vector = source.ToVector4(); - vector *= 65534; - vector -= new Vector4(32767); - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - var vector = source.ToVector4(); - vector *= 65534; - vector -= new Vector4(32767); - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - var vector = source.ToVector4(); - vector *= 65534; - vector -= new Vector4(32767); - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is Short4 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Short4 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Short4 other) - { - return this == other; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Short4 other) => this.PackedValue.Equals(other); /// /// Gets the hash code for the current instance. /// /// Hash code for the instance. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Returns a string representation of the current instance. - /// - /// String that represents the object. + /// public override string ToString() { - return this.PackedValue.ToString("x16"); + var vector = this.ToVector4(); + return FormattableString.Invariant($"Short4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong Pack(float x, float y, float z, float w) + [MethodImpl(InliningOptions.ShortMethod)] + private static ulong Pack(ref Vector4 vector) { - // Largest two byte positive number 0xFFFF >> 1; - const float MaxPos = 0x7FFF; - - // Two's complement - const float MinNeg = ~(int)MaxPos; + vector = Vector4.Clamp(vector, Min, Max); // Clamp the value between min and max values - ulong word4 = ((ulong)Math.Round(x.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x00; - ulong word3 = ((ulong)Math.Round(y.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x10; - ulong word2 = ((ulong)Math.Round(z.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x20; - ulong word1 = ((ulong)Math.Round(w.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x30; + ulong word4 = ((ulong)Math.Round(vector.X) & 0xFFFF) << 0x00; + ulong word3 = ((ulong)Math.Round(vector.Y) & 0xFFFF) << 0x10; + ulong word2 = ((ulong)Math.Round(vector.Z) & 0xFFFF) << 0x20; + ulong word1 = ((ulong)Math.Round(vector.W) & 0xFFFF) << 0x30; return word4 | word3 | word2 | word1; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector /= 65534; - vector *= 255; - vector += Half; - vector += Round; - return Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs index 5041dcf5ac..b338ff446e 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs @@ -76,8 +76,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - float threshold = this.Threshold * 255F; - Rgba32 rgba = default; + byte threshold = (byte)MathF.Round(this.Threshold * 255F); bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); @@ -89,10 +88,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // Collect the values before looping so we can reduce our calculation count for identical sibling pixels TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; - sourcePixel.ToRgba32(ref rgba); + var rgba = sourcePixel.ToRgba32(); // Convert to grayscale using ITU-R Recommendation BT.709 if required - float luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); for (int y = startY; y < endY; y++) { @@ -106,8 +105,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // rather than calculating it again. This is an inexpensive optimization. if (!previousPixel.Equals(sourcePixel)) { - sourcePixel.ToRgba32(ref rgba); - luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + rgba = sourcePixel.ToRgba32(); + luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer previousPixel = sourcePixel; diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs index 048af82619..0b28a1574b 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs @@ -56,7 +56,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - Rgba32 rgba = default; bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); @@ -68,10 +67,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // Collect the values before looping so we can reduce our calculation count for identical sibling pixels TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; - sourcePixel.ToRgba32(ref rgba); + var rgba = sourcePixel.ToRgba32(); // Convert to grayscale using ITU-R Recommendation BT.709 if required - float luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); for (int y = startY; y < endY; y++) { @@ -85,8 +84,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // rather than calculating it again. This is an inexpensive optimization. if (!previousPixel.Equals(sourcePixel)) { - sourcePixel.ToRgba32(ref rgba); - luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + rgba = sourcePixel.ToRgba32(); + luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer previousPixel = sourcePixel; diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs index 60754b3bf2..03b7f73e94 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization Rectangle sourceRectangle, Configuration configuration) { - float threshold = this.Threshold * 255F; + byte threshold = (byte)MathF.Round(this.Threshold * 255F); TPixel upper = this.UpperColor; TPixel lower = this.LowerColor; @@ -83,17 +83,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization for (int y = rows.Min; y < rows.Max; y++) { Span row = source.GetPixelRowSpan(y); - Rgba32 rgba = default; for (int x = startX; x < endX; x++) { ref TPixel color = ref row[x]; - color.ToRgba32(ref rgba); + var rgba = color.ToRgba32(); // Convert to grayscale using ITU-R Recommendation BT.709 if required - float luminance = isAlphaOnly - ? rgba.A - : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); color = luminance >= threshold ? upper : lower; } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs index 8e2b2a5a82..b60322799a 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs @@ -4,7 +4,6 @@ using System; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors.Dithering; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Dithering @@ -64,8 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - float threshold = this.Threshold * 255F; - Rgba32 rgba = default; + byte threshold = (byte)MathF.Round(this.Threshold * 255F); bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); @@ -78,10 +76,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; PixelPair pair = this.GetClosestPixelPair(ref sourcePixel); - sourcePixel.ToRgba32(ref rgba); + var rgba = sourcePixel.ToRgba32(); // Convert to grayscale using ITU-R Recommendation BT.709 if required - float luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); for (int y = startY; y < endY; y++) { @@ -103,8 +101,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering continue; } - sourcePixel.ToRgba32(ref rgba); - luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + rgba = sourcePixel.ToRgba32(); + luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer previousPixel = sourcePixel; diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs index b5e2eebc2b..149c7170ac 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs @@ -4,7 +4,6 @@ using System; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors.Dithering; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Dithering @@ -32,10 +31,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// The ordered ditherer. /// The palette to select substitute colors from. public OrderedDitherPaletteProcessor(IOrderedDither dither, TPixel[] palette) - : base(palette) - { - this.Dither = dither ?? throw new ArgumentNullException(nameof(dither)); - } + : base(palette) => this.Dither = dither ?? throw new ArgumentNullException(nameof(dither)); /// /// Gets the ditherer. @@ -45,7 +41,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - Rgba32 rgba = default; bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); @@ -58,10 +53,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; PixelPair pair = this.GetClosestPixelPair(ref sourcePixel); - sourcePixel.ToRgba32(ref rgba); + var rgba = sourcePixel.ToRgba32(); // Convert to grayscale using ITU-R Recommendation BT.709 if required - float luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); for (int y = startY; y < endY; y++) { @@ -83,8 +78,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering continue; } - sourcePixel.ToRgba32(ref rgba); - luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + rgba = sourcePixel.ToRgba32(); + luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer previousPixel = sourcePixel; diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index 39546d63f7..552aa8af82 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -73,14 +73,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization ref TPixel scanBaseRef = ref MemoryMarshal.GetReference(row); // And loop through each column - Rgba32 rgba = default; for (int x = 0; x < width; x++) { ref TPixel pixel = ref Unsafe.Add(ref scanBaseRef, x); - pixel.ToRgba32(ref rgba); // Add the color to the Octree - this.octree.AddColor(ref pixel, ref rgba); + this.octree.AddColor(ref pixel); } } } @@ -97,9 +95,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // pass of the algorithm by avoiding transforming rows of identical color. TPixel sourcePixel = source[0, 0]; TPixel previousPixel = sourcePixel; - Rgba32 rgba = default; this.transparentIndex = this.GetTransparentIndex(); - byte pixelValue = this.QuantizePixel(ref sourcePixel, ref rgba); + byte pixelValue = this.QuantizePixel(ref sourcePixel); TPixel transformedPixel = palette[pixelValue]; for (int y = 0; y < height; y++) @@ -117,7 +114,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (!previousPixel.Equals(sourcePixel)) { // Quantize the pixel - pixelValue = this.QuantizePixel(ref sourcePixel, ref rgba); + pixelValue = this.QuantizePixel(ref sourcePixel); // And setup the previous pointer previousPixel = sourcePixel; @@ -146,10 +143,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Process the pixel in the second pass of the algorithm. /// /// The pixel to quantize. - /// The color to compare against. /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - private byte QuantizePixel(ref TPixel pixel, ref Rgba32 rgba) + private byte QuantizePixel(ref TPixel pixel) { if (this.Dither) { @@ -158,13 +154,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization return this.GetClosestPixel(ref pixel); } - pixel.ToRgba32(ref rgba); + var rgba = pixel.ToRgba32(); if (rgba.Equals(default)) { return this.transparentIndex; } - return (byte)this.octree.GetPaletteIndex(ref pixel, ref rgba); + return (byte)this.octree.GetPaletteIndex(ref pixel); } /// @@ -239,8 +235,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Add a given color value to the Octree /// /// The pixel data. - /// The color. - public void AddColor(ref TPixel pixel, ref Rgba32 rgba) + public void AddColor(ref TPixel pixel) { // Check if this request is for the same color as the last if (this.previousColor.Equals(pixel)) @@ -250,18 +245,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (this.previousNode is null) { this.previousColor = pixel; - this.root.AddColor(ref pixel, this.maxColorBits, 0, this, ref rgba); + this.root.AddColor(ref pixel, this.maxColorBits, 0, this); } else { // Just update the previous node - this.previousNode.Increment(ref pixel, ref rgba); + this.previousNode.Increment(ref pixel); } } else { this.previousColor = pixel; - this.root.AddColor(ref pixel, this.maxColorBits, 0, this, ref rgba); + this.root.AddColor(ref pixel, this.maxColorBits, 0, this); } } @@ -294,12 +289,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Get the palette index for the passed color /// /// The pixel data. - /// The color to map to. /// /// The . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int GetPaletteIndex(ref TPixel pixel, ref Rgba32 rgba) => this.root.GetPaletteIndex(ref pixel, 0, ref rgba); + public int GetPaletteIndex(ref TPixel pixel) => this.root.GetPaletteIndex(ref pixel, 0); /// /// Keep track of the previous node that was quantized @@ -426,13 +420,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The number of significant color bits /// The level in the tree /// The tree to which this node belongs - /// The color to map to. - public void AddColor(ref TPixel pixel, int colorBits, int level, Octree octree, ref Rgba32 rgba) + public void AddColor(ref TPixel pixel, int colorBits, int level, Octree octree) { // Update the color information if this is a leaf if (this.leaf) { - this.Increment(ref pixel, ref rgba); + this.Increment(ref pixel); // Setup the previous node octree.TrackPrevious(this); @@ -441,7 +434,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { // Go to the next level down in the tree int shift = 7 - level; - pixel.ToRgba32(ref rgba); + var rgba = pixel.ToRgba32(); int index = ((rgba.B & Mask[level]) >> (shift - 2)) | ((rgba.G & Mask[level]) >> (shift - 1)) @@ -456,7 +449,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } // Add the color to the child node - child.AddColor(ref pixel, colorBits, level + 1, octree, ref rgba); + child.AddColor(ref pixel, colorBits, level + 1, octree); } } @@ -525,19 +518,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The pixel data. /// The level. - /// The color to map to. /// /// The representing the index of the pixel in the palette. /// [MethodImpl(MethodImplOptions.NoInlining)] - public int GetPaletteIndex(ref TPixel pixel, int level, ref Rgba32 rgba) + public int GetPaletteIndex(ref TPixel pixel, int level) { int index = this.paletteIndex; if (!this.leaf) { int shift = 7 - level; - pixel.ToRgba32(ref rgba); + var rgba = pixel.ToRgba32(); int pixelIndex = ((rgba.B & Mask[level]) >> (shift - 2)) | ((rgba.G & Mask[level]) >> (shift - 1)) @@ -546,7 +538,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization OctreeNode child = this.children[pixelIndex]; if (child != null) { - index = child.GetPaletteIndex(ref pixel, level + 1, ref rgba); + index = child.GetPaletteIndex(ref pixel, level + 1); } else { @@ -561,11 +553,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Increment the pixel count and add to the color information /// /// The pixel to add. - /// The color to map to. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Increment(ref TPixel pixel, ref Rgba32 rgba) + public void Increment(ref TPixel pixel) { - pixel.ToRgba32(ref rgba); + var rgba = pixel.ToRgba32(); this.pixelCount++; this.red += rgba.R; this.green += rgba.G; diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 13bc057da8..f3b5da3202 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -442,33 +442,36 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // Build up the 3-D color histogram // Loop through each row - for (int y = 0; y < height; y++) + using (IMemoryOwner rgbaBuffer = source.MemoryAllocator.Allocate(source.Width)) { - Span row = source.GetPixelRowSpan(y); - ref TPixel scanBaseRef = ref MemoryMarshal.GetReference(row); - - // And loop through each column - Rgba32 rgba = default; - for (int x = 0; x < width; x++) + for (int y = 0; y < height; y++) { - ref TPixel pixel = ref Unsafe.Add(ref scanBaseRef, x); - pixel.ToRgba32(ref rgba); + Span row = source.GetPixelRowSpan(y); + Span rgbaSpan = rgbaBuffer.GetSpan(); + PixelOperations.Instance.ToRgba32(row, rgbaSpan, source.Width); + ref Rgba32 scanBaseRef = ref MemoryMarshal.GetReference(rgbaSpan); + + // And loop through each column + for (int x = 0; x < width; x++) + { + ref Rgba32 rgba = ref Unsafe.Add(ref scanBaseRef, x); - int r = rgba.R >> (8 - IndexBits); - int g = rgba.G >> (8 - IndexBits); - int b = rgba.B >> (8 - IndexBits); - int a = rgba.A >> (8 - IndexAlphaBits); + int r = rgba.R >> (8 - IndexBits); + int g = rgba.G >> (8 - IndexBits); + int b = rgba.B >> (8 - IndexBits); + int a = rgba.A >> (8 - IndexAlphaBits); - int index = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1); + int index = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1); - vwtSpan[index]++; - vmrSpan[index] += rgba.R; - vmgSpan[index] += rgba.G; - vmbSpan[index] += rgba.B; - vmaSpan[index] += rgba.A; + vwtSpan[index]++; + vmrSpan[index] += rgba.R; + vmgSpan[index] += rgba.G; + vmbSpan[index] += rgba.B; + vmaSpan[index] += rgba.A; - var vector = new Vector4(rgba.R, rgba.G, rgba.B, rgba.A); - m2Span[index] += Vector4.Dot(vector, vector); + var vector = new Vector4(rgba.R, rgba.G, rgba.B, rgba.A); + m2Span[index] += Vector4.Dot(vector, vector); + } } } } @@ -876,8 +879,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } // Expected order r->g->b->a - Rgba32 rgba = default; - pixel.ToRgba32(ref rgba); + var rgba = pixel.ToRgba32(); int r = rgba.R >> (8 - IndexBits); int g = rgba.G >> (8 - IndexBits); diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index a5fa59ba07..eaa52a9750 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -3,6 +3,7 @@ // ReSharper disable InconsistentNaming +using System; using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; @@ -19,11 +20,14 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk public abstract class PackFromVector4 where TPixel : struct, IPixel { - private IMemoryOwner source; + protected IMemoryOwner source; - private IMemoryOwner destination; + protected IMemoryOwner destination; - [Params(16, 128, 512)] + [Params( + 64, + 2048 + )] public int Count { get; set; } [GlobalSetup] @@ -40,7 +44,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.source.Dispose(); } - [Benchmark(Baseline = true)] + //[Benchmark] public void PerElement() { ref Vector4 s = ref MemoryMarshal.GetReference(this.source.GetSpan()); @@ -53,13 +57,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark] - public void CommonBulk() + public void PixelOperations_Base() { new PixelOperations().PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } [Benchmark] - public void OptimizedBulk() + public void PixelOperations_Specialized() { PixelOperations.Instance.PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } @@ -67,6 +71,58 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk public class PackFromVector4_Rgba32 : PackFromVector4 { + [Benchmark] + public void FallbackIntrinsics128() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); + } + + [Benchmark(Baseline = true)] + public void BasicIntrinsics256() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); + } + + [Benchmark] + public void ExtendedIntrinsic() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); + } + // RESULTS (2018 October): + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ---------------------------- |-------- |------ |-------------:|-------------:|------------:|-------:|---------:|-------:|----------:| + // FallbackIntrinsics128 | Clr | 64 | 340.38 ns | 22.319 ns | 1.2611 ns | 1.41 | 0.01 | - | 0 B | + // BasicIntrinsics256 | Clr | 64 | 240.79 ns | 11.421 ns | 0.6453 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic | Clr | 64 | 199.09 ns | 124.239 ns | 7.0198 ns | 0.83 | 0.02 | - | 0 B | + // PixelOperations_Base | Clr | 64 | 647.99 ns | 24.003 ns | 1.3562 ns | 2.69 | 0.01 | 0.0067 | 24 B | + // PixelOperations_Specialized | Clr | 64 | 259.79 ns | 13.391 ns | 0.7566 ns | 1.08 | 0.00 | - | 0 B | <--- ceremonial overhead has been minimized! + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 64 | 234.64 ns | 12.320 ns | 0.6961 ns | 1.58 | 0.00 | - | 0 B | + // BasicIntrinsics256 | Core | 64 | 148.87 ns | 2.794 ns | 0.1579 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic | Core | 64 | 94.06 ns | 10.015 ns | 0.5659 ns | 0.63 | 0.00 | - | 0 B | + // PixelOperations_Base | Core | 64 | 573.52 ns | 31.865 ns | 1.8004 ns | 3.85 | 0.01 | 0.0067 | 24 B | + // PixelOperations_Specialized | Core | 64 | 117.21 ns | 13.264 ns | 0.7494 ns | 0.79 | 0.00 | - | 0 B | + // | | | | | | | | | | + // FallbackIntrinsics128 | Clr | 2048 | 6,735.93 ns | 2,139.340 ns | 120.8767 ns | 1.71 | 0.03 | - | 0 B | + // BasicIntrinsics256 | Clr | 2048 | 3,929.29 ns | 334.027 ns | 18.8731 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic | Clr | 2048 | 2,226.01 ns | 130.525 ns | 7.3749 ns |!! 0.57 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Clr | 2048 | 16,760.84 ns | 367.800 ns | 20.7814 ns | 4.27 | 0.02 | - | 24 B | <--- Extra copies using "Vector4 TPixel.ToVector4()" + // PixelOperations_Specialized | Clr | 2048 | 3,986.03 ns | 237.238 ns | 13.4044 ns | 1.01 | 0.00 | - | 0 B | <--- can't yet detect whether ExtendedIntrinsics are available :( + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 2048 | 6,644.65 ns | 2,677.090 ns | 151.2605 ns | 1.69 | 0.05 | - | 0 B | + // BasicIntrinsics256 | Core | 2048 | 3,923.70 ns | 1,971.760 ns | 111.4081 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic | Core | 2048 | 2,092.32 ns | 375.657 ns | 21.2253 ns |!! 0.53 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Core | 2048 | 16,875.73 ns | 1,271.957 ns | 71.8679 ns | 4.30 | 0.10 | - | 24 B | + // PixelOperations_Specialized | Core | 2048 | 2,129.92 ns | 262.888 ns | 14.8537 ns |!! 0.54 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 50fac25139..2cbe549e4a 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -6,8 +6,14 @@ using System.Buffers; using System; using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Jobs; +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Environments; +using BenchmarkDotNet.Jobs; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -17,11 +23,17 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk public abstract class ToVector4 where TPixel : struct, IPixel { - private IMemoryOwner source; + protected IMemoryOwner source; - private IMemoryOwner destination; + protected IMemoryOwner destination; - [Params(64, 300, 1024)] + [Params( + 64, + //256, + //512, + //1024, + 2048 + )] public int Count { get; set; } [GlobalSetup] @@ -38,7 +50,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.destination.Dispose(); } - [Benchmark(Baseline = true)] + //[Benchmark] public void PerElement() { Span s = this.source.GetSpan(); @@ -46,25 +58,163 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk for (int i = 0; i < this.Count; i++) { - TPixel c = s[i]; - d[i] = c.ToVector4(); + d[i] = s[i].ToVector4(); } } [Benchmark] - public void CommonBulk() + public void PixelOperations_Base() { new PixelOperations().ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } [Benchmark] - public void OptimizedBulk() + public void PixelOperations_Specialized() { PixelOperations.Instance.ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } } + [Config(typeof(Config.ShortClr))] public class ToVector4_Rgba32 : ToVector4 { + [Benchmark] + public void FallbackIntrinsics128() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + } + + [Benchmark(Baseline = true)] + public void BasicIntrinsics256() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + } + + [Benchmark] + public void ExtendedIntrinsics() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + } + + //[Benchmark] + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + int n = dFloats.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); + ref Vector destBaseU = ref Unsafe.As, Vector>(ref destBase); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + ref Vector d = ref Unsafe.Add(ref destBaseU, i * 4); + d = w0; + Unsafe.Add(ref d, 1) = w1; + Unsafe.Add(ref d, 2) = w2; + Unsafe.Add(ref d, 3) = w3; + } + + n = dFloats.Length / Vector.Count; + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + ref Vector dRef = ref Unsafe.Add(ref destBase, i); + + Vector du = Vector.AsVectorInt32(dRef); + Vector v = Vector.ConvertToSingle(du); + v *= scale; + + dRef = v; + } + } + + //[Benchmark] + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + int n = dFloats.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + Vector f0 = ConvertToNormalizedSingle(w0, scale); + Vector f1 = ConvertToNormalizedSingle(w1, scale); + Vector f2 = ConvertToNormalizedSingle(w2, scale); + Vector f3 = ConvertToNormalizedSingle(w3, scale); + + ref Vector d = ref Unsafe.Add(ref destBase, i * 4); + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector ConvertToNormalizedSingle(Vector u, Vector scale) + { + Vector vi = Vector.AsVectorInt32(u); + Vector v = Vector.ConvertToSingle(vi); + v *= scale; + return v; + } + + // RESULTS (2018 October): + // + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ---------------------------- |-------- |------ |------------:|-------------:|------------:|-------:|---------:|-------:|----------:| + // FallbackIntrinsics128 | Clr | 64 | 287.62 ns | 6.026 ns | 0.3405 ns | 1.19 | 0.00 | - | 0 B | + // BasicIntrinsics256 | Clr | 64 | 240.83 ns | 10.585 ns | 0.5981 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Clr | 64 | 168.28 ns | 11.478 ns | 0.6485 ns | 0.70 | 0.00 | - | 0 B | + // PixelOperations_Base | Clr | 64 | 334.08 ns | 38.048 ns | 2.1498 ns | 1.39 | 0.01 | 0.0072 | 24 B | + // PixelOperations_Specialized | Clr | 64 | 255.41 ns | 10.939 ns | 0.6181 ns | 1.06 | 0.00 | - | 0 B | <--- ceremonial overhead has been minimized! + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 64 | 183.29 ns | 8.931 ns | 0.5046 ns | 1.32 | 0.00 | - | 0 B | + // BasicIntrinsics256 | Core | 64 | 139.18 ns | 7.633 ns | 0.4313 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Core | 64 | 66.29 ns | 16.366 ns | 0.9247 ns | 0.48 | 0.01 | - | 0 B | + // PixelOperations_Base | Core | 64 | 257.75 ns | 16.959 ns | 0.9582 ns | 1.85 | 0.01 | 0.0072 | 24 B | + // PixelOperations_Specialized | Core | 64 | 90.14 ns | 9.955 ns | 0.5625 ns | 0.65 | 0.00 | - | 0 B | + // | | | | | | | | | | + // FallbackIntrinsics128 | Clr | 2048 | 5,011.84 ns | 347.991 ns | 19.6621 ns | 1.22 | 0.01 | - | 0 B | + // BasicIntrinsics256 | Clr | 2048 | 4,119.35 ns | 720.153 ns | 40.6900 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Clr | 2048 | 1,195.29 ns | 164.389 ns | 9.2883 ns |!! 0.29 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Clr | 2048 | 6,820.58 ns | 823.433 ns | 46.5255 ns | 1.66 | 0.02 | - | 24 B | + // PixelOperations_Specialized | Clr | 2048 | 4,203.53 ns | 176.714 ns | 9.9847 ns | 1.02 | 0.01 | - | 0 B | <--- can't yet detect whether ExtendedIntrinsics are available :( + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 2048 | 5,017.89 ns | 4,021.533 ns | 227.2241 ns | 1.24 | 0.05 | - | 0 B | + // BasicIntrinsics256 | Core | 2048 | 4,046.51 ns | 1,150.390 ns | 64.9992 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Core | 2048 | 1,130.59 ns | 832.588 ns | 47.0427 ns |!! 0.28 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Core | 2048 | 6,752.68 ns | 272.820 ns | 15.4148 ns | 1.67 | 0.02 | - | 24 B | + // PixelOperations_Specialized | Core | 2048 | 1,126.13 ns | 79.192 ns | 4.4745 ns |!! 0.28 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs index 4e9c6d10a6..f96023f000 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs @@ -4,10 +4,7 @@ // ReSharper disable InconsistentNaming using System.Buffers; -using System; - using BenchmarkDotNet.Attributes; - using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -38,35 +35,10 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark(Baseline = true)] - public void PerElement() - { - Span s = this.source.GetSpan(); - Span d = this.destination.GetSpan(); - - var rgb = default(Rgb24); - - for (int i = 0; i < this.Count; i++) - { - TPixel c = s[i]; - int i3 = i * 3; - c.ToRgb24(ref rgb); - d[i3] = rgb.R; - d[i3 + 1] = rgb.G; - d[i3 + 2] = rgb.B; - } - } + public void CommonBulk() => new PixelOperations().ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); [Benchmark] - public void CommonBulk() - { - new PixelOperations().ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } - - [Benchmark] - public void OptimizedBulk() - { - PixelOperations.Instance.ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } + public void OptimizedBulk() => PixelOperations.Instance.ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } public class ToXyz_Rgba32 : ToXyz diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs index 8166c8f465..740287e85a 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs @@ -42,13 +42,11 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk Span s = this.source.GetSpan(); Span d = this.destination.GetSpan(); - var rgba = default(Rgba32); - for (int i = 0; i < this.Count; i++) { TPixel c = s[i]; int i4 = i * 4; - c.ToRgba32(ref rgba); + var rgba = c.ToRgba32(); d[i4] = rgba.R; d[i4 + 1] = rgba.G; d[i4 + 2] = rgba.B; @@ -57,16 +55,10 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark] - public void CommonBulk() - { - new PixelOperations().ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } + public void CommonBulk() => new PixelOperations().ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); [Benchmark] - public void OptimizedBulk() - { - PixelOperations.Instance.ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } + public void OptimizedBulk() => PixelOperations.Instance.ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } public class ToXyzw_Rgba32 : ToXyzw diff --git a/tests/ImageSharp.Benchmarks/General/Abs.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs similarity index 88% rename from tests/ImageSharp.Benchmarks/General/Abs.cs rename to tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs index a67f3f1078..ea53959b6a 100644 --- a/tests/ImageSharp.Benchmarks/General/Abs.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs @@ -1,9 +1,9 @@ -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System; +using System; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ public class Abs { [Params(-1, 1)] diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs new file mode 100644 index 0000000000..3b7dea0955 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs @@ -0,0 +1,70 @@ +using System; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ + public class ClampFloat + { + private readonly float min = -1.5f; + private readonly float max = 2.5f; + private static readonly float[] Values = { -10, -5, -3, -1.5f, -0.5f, 0f, 1f, 1.5f, 2.5f, 3, 10 }; + + [Benchmark(Baseline = true)] + public float UsingMathF() + { + float acc = 0; + + for (int i = 0; i < Values.Length; i++) + { + acc += ClampUsingMathF(Values[i], this.min, this.max); + } + + return acc; + } + + [Benchmark] + public float UsingBranching() + { + float acc = 0; + + for (int i = 0; i < Values.Length; i++) + { + acc += ClampUsingBranching(Values[i], this.min, this.max); + } + + return acc; + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float ClampUsingMathF(float x, float min, float max) + { + return Math.Min(max, Math.Max(min, x)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float ClampUsingBranching(float x, float min, float max) + { + if (x >= max) + { + return max; + } + + if (x <= min) + { + return min; + } + + return x; + } + + // RESULTS: + // Method | Mean | Error | StdDev | Scaled | + // --------------- |---------:|----------:|----------:|-------:| + // UsingMathF | 30.37 ns | 0.3764 ns | 0.3337 ns | 1.00 | + // UsingBranching | 18.66 ns | 0.1043 ns | 0.0871 ns | 0.61 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Clamp.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs similarity index 93% rename from tests/ImageSharp.Benchmarks/General/Clamp.cs rename to tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs index ef6bc3c402..6ce82ba115 100644 --- a/tests/ImageSharp.Benchmarks/General/Clamp.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs @@ -3,14 +3,14 @@ // Licensed under the Apache License, Version 2.0. // -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System; - using System.Runtime.CompilerServices; +using System; +using System.Runtime.CompilerServices; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; - public class Clamp +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ + public class ClampInt32IntoByte { [Params(-1, 0, 255, 256)] public int Value { get; set; } diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs new file mode 100644 index 0000000000..9ddfad7222 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs @@ -0,0 +1,23 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Jobs; + +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ + [LongRunJob] + public class ModuloPowerOfTwoConstant + { + private readonly int value = 42; + + [Benchmark(Baseline = true)] + public int Standard() + { + return this.value % 8; + } + + [Benchmark] + public int Bitwise() + { + return ImageMaths.Modulo8(this.value); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs new file mode 100644 index 0000000000..5c2fe81fa2 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs @@ -0,0 +1,32 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Jobs; + +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ + [LongRunJob] + public class ModuloPowerOfTwoVariable + { + private readonly int value = 42; + + private readonly int m = 32; + + [Benchmark(Baseline = true)] + public int Standard() + { + return this.value % this.m; + } + + [Benchmark] + public int Bitwise() + { + return ImageMaths.ModuloP2(this.value, this.m); + } + + // RESULTS: + // + // Method | Mean | Error | StdDev | Median | Scaled | ScaledSD | + // --------- |----------:|----------:|----------:|----------:|-------:|---------:| + // Standard | 1.2465 ns | 0.0093 ns | 0.0455 ns | 1.2423 ns | 1.00 | 0.00 | + // Bitwise | 0.0265 ns | 0.0103 ns | 0.0515 ns | 0.0000 ns | 0.02 | 0.04 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Pow.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs similarity index 93% rename from tests/ImageSharp.Benchmarks/General/Pow.cs rename to tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs index 325bd9d20e..0f256fc781 100644 --- a/tests/ImageSharp.Benchmarks/General/Pow.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs @@ -1,7 +1,8 @@ using System; + using BenchmarkDotNet.Attributes; -namespace SixLabors.ImageSharp.Benchmarks.General +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath { public class Pow { diff --git a/tests/ImageSharp.Benchmarks/General/Modulus.cs b/tests/ImageSharp.Benchmarks/General/Modulus.cs deleted file mode 100644 index e6d5ccce62..0000000000 --- a/tests/ImageSharp.Benchmarks/General/Modulus.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using BenchmarkDotNet.Attributes; - - public class Modulus - { - [Benchmark(Baseline = true, Description = "Standard Modulus using %")] - public int StandardModulus() - { - return 255 % 256; - } - - [Benchmark(Description = "Bitwise Modulus using &")] - public int BitwiseModulus() - { - return 255 & 255; - } - } -} diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs new file mode 100644 index 0000000000..b5f339fb37 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs @@ -0,0 +1,28 @@ +using System.Numerics; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + interface ITestPixel + where T : struct, ITestPixel + { + void FromRgba32(Rgba32 source); + + void FromRgba32(ref Rgba32 source); + + void FromBytes(byte r, byte g, byte b, byte a); + + void FromVector4(Vector4 source); + + void FromVector4(ref Vector4 source); + + Rgba32 ToRgba32(); + + void CopyToRgba32(ref Rgba32 dest); + + Vector4 ToVector4(); + + void CopyToVector4(ref Vector4 dest); + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs similarity index 66% rename from tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromRgba32.cs rename to tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs index f5bd135e12..046c7dd90c 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs @@ -1,86 +1,15 @@ // ReSharper disable InconsistentNaming -using SixLabors.ImageSharp.PixelFormats; +using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; +using BenchmarkDotNet.Attributes; - using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.PixelFormats; +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ public class PixelConversion_ConvertFromRgba32 { - interface ITestPixel - where T : struct, ITestPixel - { - void FromRgba32(Rgba32 source); - - void FromRgba32(ref Rgba32 source); - - void FromBytes(byte r, byte g, byte b, byte a); - } - - [StructLayout(LayoutKind.Sequential)] - struct TestArgb : ITestPixel - { - private byte a, r, g, b; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(Rgba32 p) - { - this.r = p.R; - this.g = p.G; - this.b = p.B; - this.a = p.A; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(ref Rgba32 p) - { - this.r = p.R; - this.g = p.G; - this.b = p.B; - this.a = p.A; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromBytes(byte r, byte g, byte b, byte a) - { - this.r = r; - this.g = g; - this.b = b; - this.a = a; - } - } - - [StructLayout(LayoutKind.Sequential)] - struct TestRgba : ITestPixel - { - private byte r, g, b, a; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(Rgba32 source) - { - this = Unsafe.As(ref source); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(ref Rgba32 source) - { - this = Unsafe.As(ref source); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromBytes(byte r, byte g, byte b, byte a) - { - this.r = r; - this.g = g; - this.b = b; - this.a = a; - } - } - struct ConversionRunner where T : struct, ITestPixel { diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs similarity index 79% rename from tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromVector4.cs rename to tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs index 5b059e2e65..d0c8a3045c 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs @@ -1,62 +1,48 @@ // ReSharper disable InconsistentNaming -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System.Numerics; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - using BenchmarkDotNet.Attributes; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; - public class PixelConversion_ConvertFromVector4 - { - interface ITestPixel - where T : struct, ITestPixel - { - void FromVector4(Vector4 source); +using BenchmarkDotNet.Attributes; - void FromVector4(ref Vector4 source); - } +using SixLabors.ImageSharp.PixelFormats; +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_ConvertFromVector4 + { [StructLayout(LayoutKind.Sequential)] - struct TestArgb : ITestPixel + struct TestRgbaVector : ITestPixel { - private byte a, r, g, b; + private Vector4 v; [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromVector4(Vector4 p) { - this.r = (byte)p.X; - this.g = (byte)p.Y; - this.b = (byte)p.Z; - this.a = (byte)p.W; + this.v = p; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromVector4(ref Vector4 p) { - this.r = (byte)p.X; - this.g = (byte)p.Y; - this.b = (byte)p.Z; - this.a = (byte)p.W; + this.v = p; } - } - - [StructLayout(LayoutKind.Sequential)] - struct TestRgbaVector : ITestPixel - { - private Vector4 v; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromVector4(Vector4 p) - { - this.v = p; - } + public Vector4 ToVector4() => this.v; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromVector4(ref Vector4 p) + public void CopyToVector4(ref Vector4 dest) { - this.v = p; + dest = this.v; } + + public void FromRgba32(Rgba32 source) => throw new System.NotImplementedException(); + public void FromRgba32(ref Rgba32 source) => throw new System.NotImplementedException(); + public void FromBytes(byte r, byte g, byte b, byte a) => throw new System.NotImplementedException(); + public Rgba32 ToRgba32() => throw new System.NotImplementedException(); + public void CopyToRgba32(ref Rgba32 dest) => throw new System.NotImplementedException(); } struct ConversionRunner diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertToRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs similarity index 67% rename from tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertToRgba32.cs rename to tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs index 5656904fe0..d205e1e63e 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertToRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs @@ -1,14 +1,14 @@ // ReSharper disable InconsistentNaming -using SixLabors.ImageSharp.PixelFormats; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; +using BenchmarkDotNet.Attributes; - using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.PixelFormats; +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ /// /// When implementing TPixel --> Rgba32 style conversions on IPixel, should which API should we prefer? /// 1. Rgba32 ToRgba32(); @@ -18,53 +18,6 @@ namespace SixLabors.ImageSharp.Benchmarks.General /// public class PixelConversion_ConvertToRgba32 { - interface ITestPixel - where T : struct, ITestPixel - { - Rgba32 ToRgba32(); - - void CopyToRgba32(ref Rgba32 dest); - } - - [StructLayout(LayoutKind.Sequential)] - struct TestArgb : ITestPixel - { - private byte a, r, g, b; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba32 ToRgba32() - { - return new Rgba32(this.r, this.g, this.b, this.a); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyToRgba32(ref Rgba32 dest) - { - dest.R = this.r; - dest.G = this.g; - dest.B = this.b; - dest.A = this.a; - } - } - - [StructLayout(LayoutKind.Sequential)] - struct TestRgba : ITestPixel - { - private byte r, g, b, a; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba32 ToRgba32() - { - return Unsafe.As(ref this); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyToRgba32(ref Rgba32 dest) - { - dest = Unsafe.As(ref this); - } - } - struct ConversionRunner where T : struct, ITestPixel { @@ -111,7 +64,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General private ConversionRunner permutedRunner; - [Params(128)] + [Params(32)] public int Count { get; set; } [GlobalSetup] diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs new file mode 100644 index 0000000000..fff9ae9bc7 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs @@ -0,0 +1,113 @@ +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation + { + struct ConversionRunner + where T : struct, ITestPixel + { + private T[] source; + + private Rgba32[] dest; + + public ConversionRunner(int count) + { + this.source = new T[count]; + this.dest = new Rgba32[count]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunRetvalConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Rgba32 destBaseRef = ref this.dest[0]; + + Rgba32 temp; + + for (int i = 0; i < count; i++) + { + temp = Unsafe.Add(ref sourceBaseRef, i).ToRgba32(); + + // manipulate pixel before saving to dest buffer: + temp.A = 0; + + Unsafe.Add(ref destBaseRef, i) = temp; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunCopyToConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Rgba32 destBaseRef = ref this.dest[0]; + + Rgba32 temp = default; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref sourceBaseRef, i).CopyToRgba32(ref temp); + + // manipulate pixel before saving to dest buffer: + temp.A = 0; + + Unsafe.Add(ref destBaseRef, i) = temp; + } + } + } + + private ConversionRunner compatibleMemoryLayoutRunner; + + private ConversionRunner permutedRunner; + + [Params(32)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.compatibleMemoryLayoutRunner = new ConversionRunner(this.Count); + this.permutedRunner = new ConversionRunner(this.Count); + } + + [Benchmark(Baseline = true)] + public void CompatibleRetval() + { + this.compatibleMemoryLayoutRunner.RunRetvalConversion(); + } + + [Benchmark] + public void CompatibleCopyTo() + { + this.compatibleMemoryLayoutRunner.RunCopyToConversion(); + } + + [Benchmark] + public void PermutedRetval() + { + this.permutedRunner.RunRetvalConversion(); + } + + [Benchmark] + public void PermutedCopyTo() + { + this.permutedRunner.RunCopyToConversion(); + } + } + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // ----------------- |------ |----------:|----------:|----------:|-------:|---------:| + // CompatibleRetval | 32 | 53.05 ns | 0.1865 ns | 0.1557 ns | 1.00 | 0.00 | + // CompatibleCopyTo | 32 | 36.12 ns | 0.3596 ns | 0.3003 ns | 0.68 | 0.01 | + // PermutedRetval | 32 | 303.61 ns | 5.1697 ns | 4.8358 ns | 5.72 | 0.09 | + // PermutedCopyTo | 32 | 38.05 ns | 0.8053 ns | 1.2297 ns | 0.72 | 0.02 | +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs new file mode 100644 index 0000000000..29a1139912 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs @@ -0,0 +1,83 @@ +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_ConvertToVector4 + { + struct ConversionRunner + where T : struct, ITestPixel + { + private T[] source; + + private Vector4[] dest; + + public ConversionRunner(int count) + { + this.source = new T[count]; + this.dest = new Vector4[count]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunRetvalConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Vector4 destBaseRef = ref this.dest[0]; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref destBaseRef, i) = Unsafe.Add(ref sourceBaseRef, i).ToVector4(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunCopyToConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Vector4 destBaseRef = ref this.dest[0]; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref sourceBaseRef, i).CopyToVector4(ref Unsafe.Add(ref destBaseRef, i)); + } + } + } + + private ConversionRunner runner; + + [Params(32)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.runner = new ConversionRunner(this.Count); + } + + [Benchmark(Baseline = true)] + public void UseRetval() + { + this.runner.RunRetvalConversion(); + } + + [Benchmark] + public void UseCopyTo() + { + this.runner.RunCopyToConversion(); + } + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | + // ---------- |------ |---------:|----------:|----------:|-------:| + // UseRetval | 32 | 94.99 ns | 1.1199 ns | 0.9352 ns | 1.00 | + // UseCopyTo | 32 | 59.47 ns | 0.6104 ns | 0.5710 ns | 0.63 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs new file mode 100644 index 0000000000..e5eb5c6cad --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs @@ -0,0 +1,95 @@ +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_ConvertToVector4_AsPartOfCompositeOperation + { + struct ConversionRunner + where T : struct, ITestPixel + { + private T[] source; + + private Vector4[] dest; + + public ConversionRunner(int count) + { + this.source = new T[count]; + this.dest = new Vector4[count]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunRetvalConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Vector4 destBaseRef = ref this.dest[0]; + + Vector4 temp; + + for (int i = 0; i < count; i++) + { + temp = Unsafe.Add(ref sourceBaseRef, i).ToVector4(); + + // manipulate pixel before saving to dest buffer: + temp.W = 0; + + Unsafe.Add(ref destBaseRef, i) = temp; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunCopyToConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Vector4 destBaseRef = ref this.dest[0]; + + Vector4 temp = default; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref sourceBaseRef, i).CopyToVector4(ref temp); + + // manipulate pixel before saving to dest buffer: + temp.W = 0; + + Unsafe.Add(ref destBaseRef, i) = temp; + } + } + } + + private ConversionRunner runner; + + [Params(32)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.runner = new ConversionRunner(this.Count); + } + + [Benchmark(Baseline = true)] + public void UseRetval() + { + this.runner.RunRetvalConversion(); + } + + [Benchmark] + public void UseCopyTo() + { + this.runner.RunCopyToConversion(); + } + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | + // ---------- |------ |----------:|----------:|----------:|-------:| + // UseRetval | 32 | 100.35 ns | 0.4844 ns | 0.4532 ns | 1.00 | + // UseCopyTo | 32 | 53.95 ns | 0.1269 ns | 0.1125 ns | 0.54 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs new file mode 100644 index 0000000000..61a7df81d6 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs @@ -0,0 +1,89 @@ +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + [StructLayout(LayoutKind.Sequential)] + struct TestArgb : ITestPixel + { + private byte a, r, g, b; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(Rgba32 p) + { + this.r = p.R; + this.g = p.G; + this.b = p.B; + this.a = p.A; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(ref Rgba32 p) + { + this.r = p.R; + this.g = p.G; + this.b = p.B; + this.a = p.A; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromBytes(byte r, byte g, byte b, byte a) + { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(Vector4 p) + { + this.r = (byte)p.X; + this.g = (byte)p.Y; + this.b = (byte)p.Z; + this.a = (byte)p.W; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(ref Vector4 p) + { + this.r = (byte)p.X; + this.g = (byte)p.Y; + this.b = (byte)p.Z; + this.a = (byte)p.W; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgba32 ToRgba32() + { + return new Rgba32(this.r, this.g, this.b, this.a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToRgba32(ref Rgba32 dest) + { + dest.R = this.r; + dest.G = this.g; + dest.B = this.b; + dest.A = this.a; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToVector4() + { + return new Vector4(this.r, this.g, this.b, this.a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToVector4(ref Vector4 dest) + { + dest.X = this.r; + dest.Y = this.g; + dest.Z = this.b; + dest.W = this.a; + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs new file mode 100644 index 0000000000..3da7fcc4cf --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs @@ -0,0 +1,72 @@ +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + [StructLayout(LayoutKind.Sequential)] + struct TestRgba : ITestPixel + { + private byte r, g, b, a; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(Rgba32 source) + { + this = Unsafe.As(ref source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(ref Rgba32 source) + { + this = Unsafe.As(ref source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromBytes(byte r, byte g, byte b, byte a) + { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + public void FromVector4(Vector4 source) + { + throw new System.NotImplementedException(); + } + + public void FromVector4(ref Vector4 source) + { + throw new System.NotImplementedException(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgba32 ToRgba32() + { + return Unsafe.As(ref this); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToRgba32(ref Rgba32 dest) + { + dest = Unsafe.As(ref this); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToVector4() + { + return new Vector4(this.r, this.g, this.b, this.a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToVector4(ref Vector4 dest) + { + dest.X = this.r; + dest.Y = this.g; + dest.Z = this.b; + dest.W = this.a; + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs new file mode 100644 index 0000000000..ca85a350cc --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs @@ -0,0 +1,113 @@ +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization +{ + [Config(typeof(Config.ShortClr))] + public class UInt32ToSingle + { + private float[] data; + + private const int Count = 32; + + [GlobalSetup] + public void Setup() + { + this.data = new float[Count]; + } + + [Benchmark(Baseline = true)] + public void MagicMethod() + { + ref Vector b = ref Unsafe.As>(ref this.data[0]); + + int n = Count / Vector.Count; + + var bVec = new Vector(256.0f / 255.0f); + var magicFloat = new Vector(32768.0f); + var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f + var mask = new Vector(255); + + for (int i = 0; i < n; i++) + { + // union { float f; uint32_t i; } u; + // u.f = 32768.0f + x * (255.0f / 256.0f); + // return (uint8_t)u.i; + + ref Vector df = ref Unsafe.Add(ref b, i); + + var vi = Vector.AsVectorUInt32(df); + vi &= mask; + vi |= magicInt; + + var vf = Vector.AsVectorSingle(vi); + vf = (vf - magicFloat) * bVec; + + df = vf; + } + } + + [Benchmark] + public void StandardSimd() + { + int n = Count / Vector.Count; + + ref Vector bf = ref Unsafe.As>(ref this.data[0]); + ref Vector bu = ref Unsafe.As, Vector>(ref bf); + + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + Vector u = Unsafe.Add(ref bu, i); + Vector v = Vector.ConvertToSingle(u); + v *= scale; + Unsafe.Add(ref bf, i) = v; + } + } + + [Benchmark] + public void StandardSimdFromInt() + { + int n = Count / Vector.Count; + + ref Vector bf = ref Unsafe.As>(ref this.data[0]); + ref Vector bu = ref Unsafe.As, Vector>(ref bf); + + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + Vector u = Unsafe.Add(ref bu, i); + Vector v = Vector.ConvertToSingle(u); + v *= scale; + Unsafe.Add(ref bf, i) = v; + } + } + + + [Benchmark] + public void StandardSimdFromInt_RefCast() + { + int n = Count / Vector.Count; + + ref Vector bf = ref Unsafe.As>(ref this.data[0]); + ref Vector bu = ref Unsafe.As, Vector>(ref bf); + + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + ref Vector fRef = ref Unsafe.Add(ref bf, i); + + Vector du = Vector.AsVectorInt32(fRef); + Vector v = Vector.ConvertToSingle(du); + v *= scale; + + fRef = v; + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs new file mode 100644 index 0000000000..2bc3af4c98 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs @@ -0,0 +1,64 @@ +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Tuples; + +namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization +{ + [Config(typeof(Config.ShortClr))] + public class WidenBytesToUInt32 + { + private byte[] source; + + private uint[] dest; + + private const int Count = 64; + + [GlobalSetup] + public void Setup() + { + this.source = new byte[Count]; + this.dest = new uint[Count]; + } + + [Benchmark(Baseline = true)] + public void Standard() + { + const int N = Count / 8; + + ref Octet.OfByte sBase = ref Unsafe.As(ref this.source[0]); + ref Octet.OfUInt32 dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < N; i++) + { + Unsafe.Add(ref dBase, i).LoadFrom(ref Unsafe.Add(ref sBase, i)); + } + } + + [Benchmark] + public void Simd() + { + int n = Count / Vector.Count; + + ref Vector sBase = ref Unsafe.As>(ref this.source[0]); + ref Vector dBase = ref Unsafe.As>(ref this.dest[0]); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + ref Vector d = ref Unsafe.Add(ref dBase, i * 4); + d = w0; + Unsafe.Add(ref d, 1) = w1; + Unsafe.Add(ref d, 2) = w2; + Unsafe.Add(ref d, 3) = w3; + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Sandbox46/Program.cs b/tests/ImageSharp.Sandbox46/Program.cs index fa1d63878a..4d89929a03 100644 --- a/tests/ImageSharp.Sandbox46/Program.cs +++ b/tests/ImageSharp.Sandbox46/Program.cs @@ -6,14 +6,9 @@ namespace SixLabors.ImageSharp.Sandbox46 { using System; - using System.Runtime.DesignerServices; - - using SixLabors.ImageSharp.Tests; - using SixLabors.ImageSharp.Tests.Colors; using SixLabors.ImageSharp.Tests.Formats.Jpg; using SixLabors.ImageSharp.Tests.PixelFormats; using SixLabors.ImageSharp.Tests.Processing.Processors.Transforms; - using SixLabors.ImageSharp.Tests.Processing.Transforms; using Xunit.Abstractions; @@ -21,15 +16,9 @@ namespace SixLabors.ImageSharp.Sandbox46 { private class ConsoleOutput : ITestOutputHelper { - public void WriteLine(string message) - { - Console.WriteLine(message); - } + public void WriteLine(string message) => Console.WriteLine(message); - public void WriteLine(string format, params object[] args) - { - Console.WriteLine(format, args); - } + public void WriteLine(string format, params object[] args) => Console.WriteLine(format, args); } /// @@ -58,20 +47,20 @@ namespace SixLabors.ImageSharp.Sandbox46 private static void RunResizeProfilingTest() { - ResizeProfilingBenchmarks test = new ResizeProfilingBenchmarks(new ConsoleOutput()); + var test = new ResizeProfilingBenchmarks(new ConsoleOutput()); test.ResizeBicubic(2000, 2000); } private static void RunToVector4ProfilingTest() { - PixelOperationsTests.Rgba32 tests = new PixelOperationsTests.Rgba32(new ConsoleOutput()); + var tests = new PixelOperationsTests.Rgba32OperationsTests(new ConsoleOutput()); tests.Benchmark_ToVector4(); } private static void RunDecodeJpegProfilingTests() { Console.WriteLine("RunDecodeJpegProfilingTests..."); - JpegProfilingBenchmarks benchmarks = new JpegProfilingBenchmarks(new ConsoleOutput()); + var benchmarks = new JpegProfilingBenchmarks(new ConsoleOutput()); foreach (object[] data in JpegProfilingBenchmarks.DecodeJpegData) { string fileName = (string)data[0]; diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index c6c3b68f33..c63cb3438f 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Tests.Common { float[] data = new float[Vector.Count]; - var rnd = new Random(); + var rnd = new Random(seed); for (int i = 0; i < Vector.Count; i++) { @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.Tests.Common [InlineData(1, 8)] [InlineData(2, 16)] [InlineData(3, 128)] - public void BulkConvertNormalizedFloatToByte_WithRoundedData(int seed, int count) + public void BasicIntrinsics256_BulkConvertNormalizedFloatToByte_WithRoundedData(int seed, int count) { if (this.SkipOnNonAvx2()) { @@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.Tests.Common byte[] dest = new byte[count]; - SimdUtils.BulkConvertNormalizedFloatToByte(normalized, dest); + SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByte(normalized, dest); byte[] expected = orig.Select(f => (byte)(f)).ToArray(); @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.Tests.Common [InlineData(1, 8)] [InlineData(2, 16)] [InlineData(3, 128)] - public void BulkConvertNormalizedFloatToByte_WithNonRoundedData(int seed, int count) + public void BasicIntrinsics256_BulkConvertNormalizedFloatToByte_WithNonRoundedData(int seed, int count) { if (this.SkipOnNonAvx2()) { @@ -153,39 +153,147 @@ namespace SixLabors.ImageSharp.Tests.Common byte[] dest = new byte[count]; - SimdUtils.BulkConvertNormalizedFloatToByte(source, dest); + SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByte(source, dest); byte[] expected = source.Select(f => (byte)Math.Round(f * 255f)).ToArray(); Assert.Equal(expected, dest); } - private static float Clamp255(float x) => Math.Min(255f, Math.Max(0f, x)); + public static readonly TheoryData ArraySizesDivisibleBy8 = new TheoryData { 0, 8, 16, 1024 }; + public static readonly TheoryData ArraySizesDivisibleBy4 = new TheoryData { 0, 4, 8, 28, 1020 }; + + public static readonly TheoryData ArraySizesDivisibleBy32 = new TheoryData { 0, 32, 512 }; + + public static readonly TheoryData ArbitraryArraySizes = + new TheoryData + { + 0, 1, 2, 3, 4, 7, 8, 9, 15, 16, 17, 63, 64, 255, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 520, + }; [Theory] - [InlineData(1, 0)] - [InlineData(1, 8)] - [InlineData(2, 16)] - [InlineData(3, 128)] - public void BulkConvertNormalizedFloatToByteClampOverflows(int seed, int count) + [MemberData(nameof(ArraySizesDivisibleBy4))] + public void FallbackIntrinsics128_BulkConvertByteToNormalizedFloat(int count) + { + TestImpl_BulkConvertByteToNormalizedFloat( + count, + (s, d) => SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); + } + + [Theory] + [MemberData(nameof(ArraySizesDivisibleBy8))] + public void BasicIntrinsics256_BulkConvertByteToNormalizedFloat(int count) { if (this.SkipOnNonAvx2()) { return; } - float[] orig = new Random(seed).GenerateRandomRoundedFloatArray(count, -50, 444); - float[] normalized = orig.Select(f => f / 255f).ToArray(); + TestImpl_BulkConvertByteToNormalizedFloat( + count, + (s, d) => SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); + } + + [Theory] + [MemberData(nameof(ArraySizesDivisibleBy32))] + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat(int count) + { + TestImpl_BulkConvertByteToNormalizedFloat( + count, + (s, d) => SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); + } - byte[] dest = new byte[count]; + [Theory] + [MemberData(nameof(ArbitraryArraySizes))] + public void BulkConvertByteToNormalizedFloat(int count) + { + TestImpl_BulkConvertByteToNormalizedFloat( + count, + (s, d) => SimdUtils.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); + } - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(normalized, dest); + private static void TestImpl_BulkConvertByteToNormalizedFloat( + int count, + Action, Memory> convert) + { + byte[] source = new Random(count).GenerateRandomByteArray(count); + float[] result = new float[count]; + float[] expected = source.Select(b => (float)b / 255f).ToArray(); - byte[] expected = orig.Select(f => (byte)Clamp255(f)).ToArray(); + convert(source, result); - Assert.Equal(expected, dest); + Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); } + [Theory] + [MemberData(nameof(ArraySizesDivisibleBy4))] + public void FallbackIntrinsics128_BulkConvertNormalizedFloatToByteClampOverflows(int count) + { + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, + (s, d) => SimdUtils.FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesDivisibleBy8))] + public void BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows(int count) + { + if (this.SkipOnNonAvx2()) + { + return; + } + + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, + (s, d) => SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesDivisibleBy32))] + public void ExtendedIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int count) + { + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, + (s, d) => SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span) + ); + } + + [Theory] + [MemberData(nameof(ArbitraryArraySizes))] + public void BulkConvertNormalizedFloatToByteClampOverflows(int count) + { + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, + (s, d) => SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span) + ); + + // for small values, let's stress test the implementation a bit: + if (count > 0 && count < 10) + { + for (int i = 0; i < 20; i++) + { + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( + count, + (s, d) => SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span), + i + 42); + } + } + } + + private static void TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( + int count, + Action, Memory> convert, int seed = -1) + { + seed = seed > 0 ? seed : count; + float[] source = new Random(seed).GenerateRandomFloatArray(count, -0.2f, 1.2f); + byte[] expected = source.Select(NormalizedFloatToByte).ToArray(); + byte[] actual = new byte[count]; + + convert(source, actual); + + Assert.Equal(expected, actual); + } + + private static byte NormalizedFloatToByte(float f) => (byte)Math.Min(255f, Math.Max(0f, f * 255f + 0.5f)); + [Theory] [InlineData(0)] [InlineData(7)] @@ -211,7 +319,7 @@ namespace SixLabors.ImageSharp.Tests.Common float[] source = { 0, 7, 42, 255, 0.5f, 1.1f, 2.6f, 16f }; - var expected = source.Select(f => (byte)Math.Round(f)).ToArray(); + byte[] expected = source.Select(f => (byte)Math.Round(f)).ToArray(); source = source.Select(f => f / 255f).ToArray(); @@ -245,8 +353,6 @@ namespace SixLabors.ImageSharp.Tests.Common iiRef = x; - //Tuple8.OfUInt32 ii = Unsafe.As, Tuple8.OfUInt32>(ref x); - ref Tuple8.OfByte d = ref MemoryMarshal.Cast(dest)[0]; d.LoadFrom(ref ii); diff --git a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs index d65796d37f..9121649f48 100644 --- a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs @@ -283,10 +283,12 @@ namespace SixLabors.ImageSharp.Tests.Drawing { // it's diagonal, so for any (a, a) on the gradient line, for all (a-x, b+x) - +/- depending on the diagonal direction - must be the same color) TPixel colorOnDiagonal = image[i, i]; + + // TODO: This is incorrect. from -0 to < 0 ?? int orthoCount = 0; for (int offset = -orthoCount; offset < orthoCount; offset++) { - Assert.Equal(colorOnDiagonal, image[i + horizontalSign * offset, i + verticalSign * offset]); + Assert.Equal(colorOnDiagonal, image[i + (horizontalSign * offset), i + (verticalSign * offset)]); } } @@ -302,8 +304,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing [Theory] [WithBlankImages(500, 500, PixelTypes.Rgba32, 0, 0, 499, 499, new[] { 0f, .2f, .5f, .9f }, new[] { 0, 0, 1, 1 })] [WithBlankImages(500, 500, PixelTypes.Rgba32, 0, 499, 499, 0, new[] { 0f, 0.2f, 0.5f, 0.9f }, new[] { 0, 1, 2, 3 })] - [WithBlankImages(500, 500, PixelTypes.Rgba32, 499, 499, 0, 0, new[] { 0f, 0.7f, 0.8f, 0.9f}, new[] { 0, 1, 2, 0 })] - [WithBlankImages(500, 500, PixelTypes.Rgba32, 0, 0, 499, 499, new[] { 0f, .5f, 1f}, new[]{0, 1, 3})] + [WithBlankImages(500, 500, PixelTypes.Rgba32, 499, 499, 0, 0, new[] { 0f, 0.7f, 0.8f, 0.9f }, new[] { 0, 1, 2, 0 })] + [WithBlankImages(500, 500, PixelTypes.Rgba32, 0, 0, 499, 499, new[] { 0f, .5f, 1f }, new[] { 0, 1, 3 })] public void ArbitraryGradients( TestImageProvider provider, int startX, int startY, @@ -312,36 +314,36 @@ namespace SixLabors.ImageSharp.Tests.Drawing int[] stopColorCodes) where TPixel : struct, IPixel { - TPixel[] colors = { - NamedColors.Navy, NamedColors.LightGreen, NamedColors.Yellow, - NamedColors.Red - }; + TPixel[] colors = + { + NamedColors.Navy, NamedColors.LightGreen, NamedColors.Yellow, + NamedColors.Red + }; var coloringVariant = new StringBuilder(); - ColorStop[] colorStops = new ColorStop[stopPositions.Length]; - Rgba32 rgba = default; + var colorStops = new ColorStop[stopPositions.Length]; + for (int i = 0; i < stopPositions.Length; i++) { TPixel color = colors[stopColorCodes[i % colors.Length]]; float position = stopPositions[i]; - color.ToRgba32(ref rgba); colorStops[i] = new ColorStop(position, color); - coloringVariant.AppendFormat(CultureInfo.InvariantCulture, "{0}@{1};", rgba.ToHex(), position); + coloringVariant.AppendFormat(CultureInfo.InvariantCulture, "{0}@{1};", color.ToRgba32().ToHex(), position); } FormattableString variant = $"({startX},{startY})_TO_({endX},{endY})__[{coloringVariant}]"; provider.VerifyOperation( image => - { - var unicolorLinearGradientBrush = new LinearGradientBrush( - new SixLabors.Primitives.Point(startX, startY), - new SixLabors.Primitives.Point(endX, endY), - GradientRepetitionMode.None, - colorStops); + { + var unicolorLinearGradientBrush = new LinearGradientBrush( + new SixLabors.Primitives.Point(startX, startY), + new SixLabors.Primitives.Point(endX, endY), + GradientRepetitionMode.None, + colorStops); - image.Mutate(x => x.Fill(unicolorLinearGradientBrush)); - }, + image.Mutate(x => x.Fill(unicolorLinearGradientBrush)); + }, variant, false, false); diff --git a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs index 6c2979fe9e..75ef611a5c 100644 --- a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs @@ -9,6 +9,74 @@ namespace SixLabors.ImageSharp.Tests.Helpers public class ImageMathsTests { + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(2)] + [InlineData(3)] + [InlineData(4)] + [InlineData(100)] + [InlineData(123)] + [InlineData(53436353)] + public void Modulo4(int x) + { + int actual = ImageMaths.Modulo4(x); + Assert.Equal(x % 4, actual); + } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(2)] + [InlineData(6)] + [InlineData(7)] + [InlineData(8)] + [InlineData(100)] + [InlineData(123)] + [InlineData(53436353)] + [InlineData(975)] + public void Modulo8(int x) + { + int actual = ImageMaths.Modulo8(x); + Assert.Equal(x % 8, actual); + } + + [Theory] + [InlineData(0, 2)] + [InlineData(1, 2)] + [InlineData(2, 2)] + [InlineData(0, 4)] + [InlineData(3, 4)] + [InlineData(5, 4)] + [InlineData(5, 8)] + [InlineData(8, 8)] + [InlineData(8, 16)] + [InlineData(15, 16)] + [InlineData(17, 16)] + [InlineData(17, 32)] + [InlineData(31, 32)] + [InlineData(32, 32)] + [InlineData(33, 32)] + public void Modulo2P(int x, int m) + { + int actual = ImageMaths.ModuloP2(x, m); + Assert.Equal(x % m, actual); + } + + [Theory] + [InlineData(0, 0, 0, 0)] + [InlineData(0.5f, 0, 1, 0.5f)] + [InlineData(-0.5f, -0.1f, 10, -0.1f)] + [InlineData(-0.05f, -0.1f, 10, -0.05f)] + [InlineData(9.9f, -0.1f, 10, 9.9f)] + [InlineData(10f, -0.1f, 10, 10f)] + [InlineData(10.1f, -0.1f, 10, 10f)] + public void Clamp(float x, float min, float max, float expected) + { + float actual = x.Clamp(min, max); + Assert.Equal(expected, actual); + } + [Fact] public void FasAbsResultMatchesMath() { diff --git a/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs b/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs index f092da7082..629b3cdeb3 100644 --- a/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs +++ b/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs @@ -1,9 +1,9 @@ -using System; -using System.Runtime.CompilerServices; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +using System; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; - using Xunit; namespace SixLabors.ImageSharp.Tests.Helpers @@ -35,4 +35,4 @@ namespace SixLabors.ImageSharp.Tests.Helpers } } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 5ef8f0111f..5d163917cd 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -2,7 +2,7 @@ net462;net471;netcoreapp2.1 True - 7.3 + latest full portable True @@ -11,15 +11,15 @@ AnyCPU;x64;x86 - true + false - true + false - true + false diff --git a/tests/ImageSharp.Tests/Issues/Issue594.cs b/tests/ImageSharp.Tests/Issues/Issue594.cs index 81fd59885a..4a0683fba7 100644 --- a/tests/ImageSharp.Tests/Issues/Issue594.cs +++ b/tests/ImageSharp.Tests/Issues/Issue594.cs @@ -48,46 +48,46 @@ namespace SixLabors.ImageSharp.Tests.Issues Assert.Equal((uint)958796544, new NormalizedByte4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue); - var rgb = default(Rgb24); - var rgba = default(Rgba32); - var bgr = default(Bgr24); - var bgra = default(Bgra32); - var argb = default(Argb32); + //var rgb = default(Rgb24); + //var rgba = default(Rgba32); + //var bgr = default(Bgr24); + //var bgra = default(Bgra32); + //var argb = default(Argb32); - new NormalizedByte4(x, y, z, w).ToRgb24(ref rgb); - Assert.Equal(rgb, new Rgb24(141, 90, 192)); + //new NormalizedByte4(x, y, z, w).ToRgb24(ref rgb); + //Assert.Equal(rgb, new Rgb24(141, 90, 192)); - new NormalizedByte4(x, y, z, w).ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); + //new NormalizedByte4(x, y, z, w).ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); - new NormalizedByte4(x, y, z, w).ToBgr24(ref bgr); - Assert.Equal(bgr, new Bgr24(141, 90, 192)); + //new NormalizedByte4(x, y, z, w).ToBgr24(ref bgr); + //Assert.Equal(bgr, new Bgr24(141, 90, 192)); - new NormalizedByte4(x, y, z, w).ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) + //new NormalizedByte4(x, y, z, w).ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) - new NormalizedByte4(x, y, z, w).ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(141, 90, 192, 39)); + //new NormalizedByte4(x, y, z, w).ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(141, 90, 192, 39)); // http://community.monogame.net/t/normalizedbyte4-texture2d-gives-different-results-from-xna/8012/8 - var r = default(NormalizedByte4); - r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); - r.ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); - - r.PackedValue = 0xff4af389; - r.ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); - - r = default(NormalizedByte4); - r.PackFromArgb32(new Argb32(9, 115, 202, 127)); - r.ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(9, 115, 202, 127)); - - r = default(NormalizedByte4); - r.PackFromBgra32(new Bgra32(9, 115, 202, 127)); - r.ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); + //var r = default(NormalizedByte4); + //r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); + //r.ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); + + //r.PackedValue = 0xff4af389; + //r.ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); + + //r = default(NormalizedByte4); + //r.PackFromArgb32(new Argb32(9, 115, 202, 127)); + //r.ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(9, 115, 202, 127)); + + //r = default(NormalizedByte4); + //r.PackFromBgra32(new Bgra32(9, 115, 202, 127)); + //r.ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); } // This test fails for unknown reason in Release mode on linux and is meant to help reproducing the issue @@ -127,41 +127,41 @@ namespace SixLabors.ImageSharp.Tests.Issues Assert.Equal(0xa6674000d99a0ccd, new NormalizedShort4(x, y, z, w).PackedValue); Assert.Equal((ulong)4150390751449251866, new NormalizedShort4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue); - var rgb = default(Rgb24); - var rgba = default(Rgba32); - var bgr = default(Bgr24); - var bgra = default(Bgra32); - var argb = default(Argb32); + //var rgb = default(Rgb24); + //var rgba = default(Rgba32); + //var bgr = default(Bgr24); + //var bgra = default(Bgra32); + //var argb = default(Argb32); - new NormalizedShort4(x, y, z, w).ToRgb24(ref rgb); - Assert.Equal(rgb, new Rgb24(141, 90, 192)); + //new NormalizedShort4(x, y, z, w).ToRgb24(ref rgb); + //Assert.Equal(rgb, new Rgb24(141, 90, 192)); - new NormalizedShort4(x, y, z, w).ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) + //new NormalizedShort4(x, y, z, w).ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) - new NormalizedShort4(x, y, z, w).ToBgr24(ref bgr); - Assert.Equal(bgr, new Bgr24(141, 90, 192)); + //new NormalizedShort4(x, y, z, w).ToBgr24(ref bgr); + //Assert.Equal(bgr, new Bgr24(141, 90, 192)); - new NormalizedShort4(x, y, z, w).ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); + //new NormalizedShort4(x, y, z, w).ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); - new NormalizedShort4(x, y, z, w).ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(141, 90, 192, 39)); + //new NormalizedShort4(x, y, z, w).ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(141, 90, 192, 39)); - var r = default(NormalizedShort4); - r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); - r.ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); + //var r = default(NormalizedShort4); + //r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); + //r.ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); - r = default(NormalizedShort4); - r.PackFromBgra32(new Bgra32(9, 115, 202, 127)); - r.ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); + //r = default(NormalizedShort4); + //r.PackFromBgra32(new Bgra32(9, 115, 202, 127)); + //r.ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); - r = default(NormalizedShort4); - r.PackFromArgb32(new Argb32(9, 115, 202, 127)); - r.ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(9, 115, 202, 127)); + //r = default(NormalizedShort4); + //r.PackFromArgb32(new Argb32(9, 115, 202, 127)); + //r.ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(9, 115, 202, 127)); } // This test fails for unknown reason in Release mode on linux and is meant to help reproducing the issue @@ -212,41 +212,41 @@ namespace SixLabors.ImageSharp.Tests.Issues w = 193; Assert.Equal((ulong)0x00c173b7316d2d1b, new Short4(x, y, z, w).PackedValue); - var rgb = default(Rgb24); - var rgba = default(Rgba32); - var bgr = default(Bgr24); - var bgra = default(Bgra32); - var argb = default(Argb32); + //var rgb = default(Rgb24); + //var rgba = default(Rgba32); + //var bgr = default(Bgr24); + //var bgra = default(Bgra32); + //var argb = default(Argb32); - new Short4(x, y, z, w).ToRgb24(ref rgb); - Assert.Equal(rgb, new Rgb24(172, 177, 243)); // this assert fails in Release build on linux (#594) + //new Short4(x, y, z, w).ToRgb24(ref rgb); + //Assert.Equal(rgb, new Rgb24(172, 177, 243)); // this assert fails in Release build on linux (#594) - new Short4(x, y, z, w).ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(172, 177, 243, 128)); + //new Short4(x, y, z, w).ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(172, 177, 243, 128)); - new Short4(x, y, z, w).ToBgr24(ref bgr); - Assert.Equal(bgr, new Bgr24(172, 177, 243)); + //new Short4(x, y, z, w).ToBgr24(ref bgr); + //Assert.Equal(bgr, new Bgr24(172, 177, 243)); - new Short4(x, y, z, w).ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(172, 177, 243, 128)); + //new Short4(x, y, z, w).ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(172, 177, 243, 128)); - new Short4(x, y, z, w).ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(172, 177, 243, 128)); + //new Short4(x, y, z, w).ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(172, 177, 243, 128)); - var r = default(Short4); - r.PackFromRgba32(new Rgba32(20, 38, 0, 255)); - r.ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(20, 38, 0, 255)); + //var r = default(Short4); + //r.PackFromRgba32(new Rgba32(20, 38, 0, 255)); + //r.ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(20, 38, 0, 255)); - r = default(Short4); - r.PackFromBgra32(new Bgra32(20, 38, 0, 255)); - r.ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(20, 38, 0, 255)); + //r = default(Short4); + //r.PackFromBgra32(new Bgra32(20, 38, 0, 255)); + //r.ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(20, 38, 0, 255)); - r = default(Short4); - r.PackFromArgb32(new Argb32(20, 38, 0, 255)); - r.ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(20, 38, 0, 255)); + //r = default(Short4); + //r.PackFromArgb32(new Argb32(20, 38, 0, 255)); + //r.ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(20, 38, 0, 255)); } // Comparison helpers with small tolerance to allow for floating point rounding during computations. diff --git a/tests/ImageSharp.Tests/Numerics/RationalTests.cs b/tests/ImageSharp.Tests/Numerics/RationalTests.cs index a9b9106c5c..caddd49216 100644 --- a/tests/ImageSharp.Tests/Numerics/RationalTests.cs +++ b/tests/ImageSharp.Tests/Numerics/RationalTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.Primitives; using Xunit; diff --git a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs index 9a29236dba..37e7d94e4d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs @@ -10,200 +10,87 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public class Alpha8Tests { [Fact] - public void Alpha8_PackedValue() + public void Alpha8_Constructor() { // Test the limits. - Assert.Equal(0x0, new Alpha8(0F).PackedValue); - Assert.Equal(0xFF, new Alpha8(1F).PackedValue); + Assert.Equal(byte.MinValue, new Alpha8(0F).PackedValue); + Assert.Equal(byte.MaxValue, new Alpha8(1F).PackedValue); // Test clamping. - Assert.Equal(0x0, new Alpha8(-1234F).PackedValue); - Assert.Equal(0xFF, new Alpha8(1234F).PackedValue); + Assert.Equal(byte.MinValue, new Alpha8(-1234F).PackedValue); + Assert.Equal(byte.MaxValue, new Alpha8(1234F).PackedValue); // Test ordering - Assert.Equal(124, new Alpha8(124F / 0xFF).PackedValue); + Assert.Equal(124, new Alpha8(124F / byte.MaxValue).PackedValue); Assert.Equal(26, new Alpha8(0.1F).PackedValue); } [Fact] - public void Alpha8_ToVector4() + public void Alpha8_Equality() { - // arrange - var alpha = new Alpha8(.5F); - - // act - var actual = alpha.ToVector4(); + var left = new Alpha8(16); + var right = new Alpha8(32); - // assert - Assert.Equal(0, actual.X); - Assert.Equal(0, actual.Y); - Assert.Equal(0, actual.Z); - Assert.Equal(.5F, actual.W, 2); - } - - [Fact] - public void Alpha8_ToScaledVector4() - { - // arrange - var alpha = new Alpha8(.5F); - - // act - Vector4 actual = alpha.ToScaledVector4(); - - // assert - Assert.Equal(0, actual.X); - Assert.Equal(0, actual.Y); - Assert.Equal(0, actual.Z); - Assert.Equal(.5F, actual.W, 2); + Assert.True(left == new Alpha8(16)); + Assert.True(left != right); + Assert.Equal(left, (object)new Alpha8(16)); } [Fact] public void Alpha8_PackFromScaledVector4() { - // arrange + // Arrange Alpha8 alpha = default; int expected = 128; Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - // act + // Act alpha.PackFromScaledVector4(scaled); byte actual = alpha.PackedValue; - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToRgb24() - { - // arrange - Rgb24 actual = default; - Alpha8 alpha = default; - var expected = new Rgb24(0, 0, 0); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToRgba32() - { - // arrange - Rgba32 actual = default; - Alpha8 alpha = default; - var expected = new Rgba32(0, 0, 0, 128); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToBgr24() - { - // arrange - Bgr24 actual = default; - Alpha8 alpha = default; - var expected = new Bgr24(0, 0, 0); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToBgra32() - { - // arrange - Bgra32 actual = default; - Alpha8 alpha = default; - var expected = new Bgra32(0, 0, 0, 128); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToArgb32() - { - // arrange - Alpha8 alpha = default; - Argb32 actual = default; - var expected = new Argb32(0, 0, 0, 128); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToArgb32(ref actual); - - // assert + // Assert Assert.Equal(expected, actual); } [Fact] - public void Alpha8_PackFromScaledVector4_ToRgba64() + public void Alpha8_ToScaledVector4() { - // arrange - Alpha8 alpha = default; - Rgba64 actual = default; - var expected = new Rgba64(0, 0, 0, 65535); - Vector4 scaled = new Alpha8(1F).ToScaledVector4(); + // Arrange + var alpha = new Alpha8(.5F); - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToRgba64(ref actual); + // Act + Vector4 actual = alpha.ToScaledVector4(); - // assert - Assert.Equal(expected, actual); + // Assert + Assert.Equal(0, actual.X); + Assert.Equal(0, actual.Y); + Assert.Equal(0, actual.Z); + Assert.Equal(.5F, actual.W, 2); } [Fact] - public void Alpha8_PackFromRgb48_ToRgb48() + public void Alpha8_ToVector4() { - // arrange - var alpha = default(Alpha8); - var actual = default(Rgb48); - var expected = new Rgb48(0, 0, 0); + // Arrange + var alpha = new Alpha8(.5F); - // act - alpha.PackFromRgb48(expected); - alpha.ToRgb48(ref actual); + // Act + var actual = alpha.ToVector4(); - // assert - Assert.Equal(expected, actual); + // Assert + Assert.Equal(0, actual.X); + Assert.Equal(0, actual.Y); + Assert.Equal(0, actual.Z); + Assert.Equal(.5F, actual.W, 2); } [Fact] - public void Alpha8_PackFromRgba64_ToRgba64() + public void Alpha8_ToRgba32() { - // arrange - var alpha = default(Alpha8); - var actual = default(Rgba64); - var expected = new Rgba64(0, 0, 0, 65535); - - // act - alpha.PackFromRgba64(expected); - alpha.ToRgba64(ref actual); + var input = new Alpha8(128); + var expected = new Rgba32(0, 0, 0, 128); - // assert + var actual = input.ToRgba32(); Assert.Equal(expected, actual); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs index 5817b5c329..6186793c5b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -66,160 +66,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.Zero, new Argb32(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One, new Argb32(Vector4.One * +1234.0f).ToVector4()); } - - [Fact] - public void Argb32_ToRgb24() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(0x1a, 0, 0x80); - - // act - argb.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_ToRgba32() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(0x1a, 0, 0x80, 0); - - // act - argb.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_ToBgr24() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(0x1a, 0, 0x80); - - // act - argb.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_ToBgra32() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(0x1a, 0, 0x80, 0); - - // act - argb.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_ToArgb32() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(0x1a, 0, 0x80, 0); - - // act - argb.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromRgba32_ToRgba32() - { - // arrange - var argb = default(Argb32); - var actual = default(Rgba32); - var expected = new Rgba32(0x1a, 0, 0x80, 0); - - // act - argb.PackFromRgba32(expected); - argb.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromBgra32_ToBgra32() - { - // arrange - var argb = default(Argb32); - var actual = default(Bgra32); - var expected = new Bgra32(0x1a, 0, 0x80, 0); - - // act - argb.PackFromBgra32(expected); - argb.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromArgb32_ToArgb32() - { - // arrange - var argb = default(Argb32); - var actual = default(Argb32); - var expected = new Argb32(0x1a, 0, 0x80, 0); - - // act - argb.PackFromArgb32(expected); - argb.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromRgb48_ToRgb48() - { - // arrange - var argb = default(Argb32); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - argb.PackFromRgb48(expected); - argb.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromRgba64_ToRgba64() - { - // arrange - var argb = default(Argb32); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - argb.PackFromRgba64(expected); - argb.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs index 048a38380e..96589a03e0 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -95,81 +95,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); } - - [Fact] - public void ToRgb24() - { - var rgb = new Bgr24(1, 2, 3); - var dest = default(Rgb24); - - rgb.ToRgb24(ref dest); - - Assert.Equal(new Rgb24(1, 2, 3), dest); - } - - [Fact] - public void ToRgba32() - { - var rgb = new Bgr24(1, 2, 3); - var rgba = default(Rgba32); - - rgb.ToRgba32(ref rgba); - - Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); - } - - [Fact] - public void ToBgr24() - { - var rgb = new Bgr24(1, 2, 3); - var bgr = default(Bgr24); - - rgb.ToBgr24(ref bgr); - - Assert.Equal(new Bgr24(1, 2, 3), bgr); - } - - [Fact] - public void ToBgra32() - { - var rgb = new Bgr24(1, 2, 3); - var bgra = default(Bgra32); - - rgb.ToBgra32(ref bgra); - - Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); - } - - [Fact] - public void Bgr24_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgr24); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr24_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgr24); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs index b66cac9ca3..8cbbf558d8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -69,112 +69,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector3.Zero, new Bgr565(Vector3.One * -1234F).ToVector3()); Assert.Equal(Vector3.One, new Bgr565(Vector3.One * 1234F).ToVector3()); } - - [Fact] - public void Bgr565_ToRgb24() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Rgb24); - var expected = new Rgb24(25, 0, 132); - - // act - bgra.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_ToRgba32() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Rgba32); - var expected = new Rgba32(25, 0, 132, 255); - - // act - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_ToBgr24() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Bgr24); - var expected = new Bgr24(25, 0, 132); - - // act - bgra.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_ToBgra32() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Bgra32); - var expected = new Bgra32(25, 0, 132, 255); - - // act - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_ToArgb32() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Argb32); - var expected = new Argb32(25, 0, 132, 255); - - // act - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgr565); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgr565); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index 70f8c35dfc..1b890ac494 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -102,81 +102,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vec(1, 2, 3, 4), rgb.ToVector4()); } - - [Fact] - public void ToRgb24() - { - var c = new Bgra32(1, 2, 3, 4); - var dest = default(Rgb24); - - c.ToRgb24(ref dest); - - Assert.Equal(new Rgb24(1, 2, 3), dest); - } - - [Fact] - public void ToRgba32() - { - var c = new Bgra32(1, 2, 3, 4); - var rgba = default(Rgba32); - - c.ToRgba32(ref rgba); - - Assert.Equal(new Rgba32(1, 2, 3, 4), rgba); - } - - [Fact] - public void ToBgr24() - { - var rgb = new Bgra32(1, 2, 3, 4); - var bgr = default(Bgr24); - - rgb.ToBgr24(ref bgr); - - Assert.Equal(new Bgr24(1, 2, 3), bgr); - } - - [Fact] - public void ToBgra32() - { - var rgb = new Bgra32(1, 2, 3, 4); - var bgra = default(Bgra32); - - rgb.ToBgra32(ref bgra); - - Assert.Equal(new Bgra32(1, 2, 3, 4), bgra); - } - - [Fact] - public void Bgra32_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgra32); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra32_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgra32); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs index f643d152ef..a2fc1a0520 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -70,160 +70,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.Zero, new Bgra4444(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One, new Bgra4444(Vector4.One * 1234.0f).ToVector4()); } - - [Fact] - public void Bgra4444_ToRgb24() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(34, 0, 136); - - // act - bgra.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_ToRgba32() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(34, 0, 136, 0); - - // act - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_ToBgr24() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(34, 0, 136); - - // act - bgra.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_ToBgra32() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(34, 0, 136, 0); - - // act - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_ToArgb32() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(34, 0, 136, 0); - - // act - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromRgba32_ToRgba32() - { - // arrange - var bgra = default(Bgra4444); - var actual = default(Rgba32); - var expected = new Rgba32(34, 0, 136, 0); - - // act - bgra.PackFromRgba32(expected); - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromBgra32_ToBgra32() - { - // arrange - var bgra = default(Bgra4444); - var actual = default(Bgra32); - var expected = new Bgra32(34, 0, 136, 0); - - // act - bgra.PackFromBgra32(expected); - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromArgb32_ToArgb32() - { - // arrange - var bgra = default(Bgra4444); - var actual = default(Argb32); - var expected = new Argb32(34, 0, 136, 0); - - // act - bgra.PackFromArgb32(expected); - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgra4444); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgra4444); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs index b6a0780312..084dfbd97c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs @@ -69,160 +69,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.Zero, new Bgra5551(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One, new Bgra5551(Vector4.One * 1234.0f).ToVector4()); } - - [Fact] - public void Bgra5551_ToRgb24() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(24, 0, 131); - - // act - bgra.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_Rgba32() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(24, 0, 131, 0); - - // act - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_ToBgr24() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(24, 0, 131); - - // act - bgra.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_Bgra32() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(24, 0, 131, 0); - - // act - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_ToArgb32() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(24, 0, 131, 0); - - // act - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromRgba32_ToRgba32() - { - // arrange - var bgra = default(Bgra5551); - var expected = new Rgba32(24, 0, 131, 0); - var actual = default(Rgba32); - - // act - bgra.PackFromRgba32(expected); - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromBgra32_ToBgra32() - { - // arrange - var bgra = default(Bgra5551); - var expected = new Bgra32(24, 0, 131, 0); - var actual = default(Bgra32); - - // act - bgra.PackFromBgra32(expected); - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromArgb32_ToArgb32() - { - // arrange - var bgra = default(Bgra5551); - var expected = new Argb32(24, 0, 131, 0); - var actual = default(Argb32); - - // act - bgra.PackFromArgb32(expected); - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgra5551); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgra5551); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs index 28555a7dff..de1c749f6c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs @@ -67,160 +67,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.Zero, new Byte4(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One * 255, new Byte4(Vector4.One * 1234.0f).ToVector4()); } - - [Fact] - public void Byte4_ToRgb24() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(128, 0, 0); - - // act - byte4.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_Rgba32() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(128, 0, 0, 0); - - // act - byte4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_ToBgr24() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(128, 0, 0); - - // act - byte4.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_Bgra32() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(128, 0, 0, 0); - - // act - byte4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_Argb32() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(128, 0, 0, 0); - - // act - byte4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromRgba32_ToRgba32() - { - // arrange - var byte4 = default(Byte4); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 0, 255); - - // act - byte4.PackFromRgba32(expected); - byte4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromBgra32_ToBgra32() - { - // arrange - var byte4 = default(Byte4); - var actual = default(Bgra32); - var expected = new Bgra32(20, 38, 0, 255); - - // act - byte4.PackFromBgra32(expected); - byte4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromArgb32_ToArgb32() - { - // arrange - var byte4 = default(Byte4); - var actual = default(Argb32); - var expected = new Argb32(20, 38, 0, 255); - - // act - byte4.PackFromArgb32(expected); - byte4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Byte4); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Byte4); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/ColorConstructorTests.cs b/tests/ImageSharp.Tests/PixelFormats/ColorConstructorTests.cs deleted file mode 100644 index b0d5929f49..0000000000 --- a/tests/ImageSharp.Tests/PixelFormats/ColorConstructorTests.cs +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Collections.Generic; -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.Colors -{ - public class ColorConstructorTests - { - public static IEnumerable Vector4Data - { - get - { - Vector4[] vector4Values = new Vector4[] - { - Vector4.Zero, - Vector4.One, - Vector4.UnitX, - Vector4.UnitY, - Vector4.UnitZ, - Vector4.UnitW, - }; - - foreach (Vector4 vector4 in vector4Values) - { - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { new Argb32(vector4), vector4Components }; - yield return new object[] { new Bgra4444(vector4), vector4Components }; - yield return new object[] { new Bgra5551(vector4), vector4Components }; - yield return new object[] { new Byte4(vector4), vector4Components }; - yield return new object[] { new HalfVector4(vector4), vector4Components }; - yield return new object[] { new NormalizedByte4(vector4), vector4Components }; - yield return new object[] { new NormalizedShort4(vector4), vector4Components }; - yield return new object[] { new Rgba1010102(vector4), vector4Components }; - yield return new object[] { new Rgba64(vector4), vector4Components }; - yield return new object[] { new Short4(vector4), vector4Components }; - } - } - } - - public static IEnumerable Vector3Data - { - get - { - Dictionary vector3Values = new Dictionary() - { - { Vector3.One, Vector4.One }, - { Vector3.Zero, new Vector4(0, 0, 0, 1) }, - { Vector3.UnitX, new Vector4(1, 0, 0, 1) }, - { Vector3.UnitY, new Vector4(0, 1, 0, 1) }, - { Vector3.UnitZ, new Vector4(0, 0, 1, 1) }, - }; - - foreach (Vector3 vector3 in vector3Values.Keys) - { - Vector4 vector4 = vector3Values[vector3]; - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { new Argb32(vector3), vector4Components }; - yield return new object[] { new Bgr565(vector3), vector4Components }; - } - } - } - - public static IEnumerable Float4Data - { - get - { - Vector4[] vector4Values = new Vector4[] - { - Vector4.Zero, - Vector4.One, - Vector4.UnitX, - Vector4.UnitY, - Vector4.UnitZ, - Vector4.UnitW, - }; - - foreach (Vector4 vector4 in vector4Values) - { - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { new Argb32(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Bgra4444(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Bgra5551(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Byte4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new HalfVector4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new NormalizedByte4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new NormalizedShort4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Rgba1010102(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Rgba64(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Short4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - } - } - } - - public static IEnumerable Float3Data - { - get - { - Dictionary vector3Values = new Dictionary() - { - { Vector3.One, Vector4.One }, - { Vector3.Zero, new Vector4(0, 0, 0, 1) }, - { Vector3.UnitX, new Vector4(1, 0, 0, 1) }, - { Vector3.UnitY, new Vector4(0, 1, 0, 1) }, - { Vector3.UnitZ, new Vector4(0, 0, 1, 1) }, - }; - - foreach (Vector3 vector3 in vector3Values.Keys) - { - Vector4 vector4 = vector3Values[vector3]; - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { new Argb32(vector3.X, vector3.Y, vector3.Z), vector4Components }; - yield return new object[] { new Bgr565(vector3.X, vector3.Y, vector3.Z), vector4Components }; - } - } - } - - [Theory] - [MemberData(nameof(Vector4Data))] - [MemberData(nameof(Vector3Data))] - [MemberData(nameof(Float4Data))] - [MemberData(nameof(Float3Data))] - public void ConstructorToVector4(IPixel packedVector, float[] expectedVector4Components) - { - // Arrange - int precision = 2; - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - Vector4 expectedVector4 = new Vector4(expectedVector4Components[0], expectedVector4Components[1], expectedVector4Components[2], expectedVector4Components[3]); - - // Act - Vector4 vector4 = packedVector.ToVector4(); - - // Assert - Assert.Equal(expectedVector4.X, vector4.X, precision); - Assert.Equal(expectedVector4.Y, vector4.Y, precision); - Assert.Equal(expectedVector4.Z, vector4.Z, precision); - Assert.Equal(expectedVector4.W, vector4.W, precision); - } - } -} diff --git a/tests/ImageSharp.Tests/PixelFormats/ColorEqualityTests.cs b/tests/ImageSharp.Tests/PixelFormats/ColorEqualityTests.cs deleted file mode 100644 index d3815f2eb6..0000000000 --- a/tests/ImageSharp.Tests/PixelFormats/ColorEqualityTests.cs +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.Colors -{ - /// - /// Test implementations of IEquatable - /// - public class ColorEqualityTests - { - public static readonly TheoryData EqualityData = - new TheoryData() - { - { new Alpha8(.5F), new Alpha8(.5F), typeof(Alpha8) }, - { new Argb32(Vector4.One), new Argb32(Vector4.One), typeof(Argb32) }, - { new Bgr565(Vector3.One), new Bgr565(Vector3.One), typeof(Bgr565) }, - { new Bgra4444(Vector4.One), new Bgra4444(Vector4.One), typeof(Bgra4444) }, - { new Bgra5551(Vector4.One), new Bgra5551(Vector4.One), typeof(Bgra5551) }, - { new Byte4(Vector4.One * 255), new Byte4(Vector4.One * 255), typeof(Byte4) }, - { new HalfSingle(-1F), new HalfSingle(-1F), typeof(HalfSingle) }, - { new HalfVector2(0.1f, -0.3f), new HalfVector2(0.1f, -0.3f), typeof(HalfVector2) }, - { new HalfVector4(Vector4.One), new HalfVector4(Vector4.One), typeof(HalfVector4) }, - { new NormalizedByte2(-Vector2.One), new NormalizedByte2(-Vector2.One), typeof(NormalizedByte2) }, - { new NormalizedByte4(Vector4.One), new NormalizedByte4(Vector4.One), typeof(NormalizedByte4) }, - { new NormalizedShort2(Vector2.One), new NormalizedShort2(Vector2.One), typeof(NormalizedShort2) }, - { new NormalizedShort4(Vector4.One), new NormalizedShort4(Vector4.One), typeof(NormalizedShort4) }, - { new Rg32(Vector2.One), new Rg32(Vector2.One), typeof(Rg32) }, - { new Rgba1010102(Vector4.One), new Rgba1010102(Vector4.One), typeof(Rgba1010102) }, - { new Rgba32(Vector4.One), new Rgba32(Vector4.One), typeof(Rgba32) }, - { new Rgba64(Vector4.One), new Rgba64(Vector4.One), typeof(Rgba64) }, - { new Short2(Vector2.One * 0x7FFF), new Short2(Vector2.One * 0x7FFF), typeof(Short2) }, - { new Short4(Vector4.One * 0x7FFF), new Short4(Vector4.One * 0x7FFF), typeof(Short4) }, - }; - - public static readonly TheoryData NotEqualityDataNulls = - new TheoryData() - { - // Valid object against null - { new Alpha8(.5F), null, typeof(Alpha8) }, - { new Argb32(Vector4.One), null, typeof(Argb32) }, - { new Bgr565(Vector3.One), null, typeof(Bgr565) }, - { new Bgra4444(Vector4.One), null, typeof(Bgra4444) }, - { new Bgra5551(Vector4.One), null, typeof(Bgra5551) }, - { new Byte4(Vector4.One * 255), null, typeof(Byte4) }, - { new HalfSingle(-1F), null, typeof(HalfSingle) }, - { new HalfVector2(0.1f, -0.3f), null, typeof(HalfVector2) }, - { new HalfVector4(Vector4.One), null, typeof(HalfVector4) }, - { new NormalizedByte2(-Vector2.One), null, typeof(NormalizedByte2) }, - { new NormalizedByte4(Vector4.One), null, typeof(NormalizedByte4) }, - { new NormalizedShort2(Vector2.One), null, typeof(NormalizedShort2) }, - { new NormalizedShort4(Vector4.One), null, typeof(NormalizedShort4) }, - { new Rg32(Vector2.One), null, typeof(Rg32) }, - { new Rgba1010102(Vector4.One), null, typeof(Rgba1010102) }, - { new Rgba64(Vector4.One), null, typeof(Rgba64) }, - { new Short2(Vector2.One * 0x7FFF), null, typeof(Short2) }, - { new Short4(Vector4.One * 0x7FFF), null, typeof(Short4) }, - }; - - public static readonly TheoryData NotEqualityDataDifferentObjects = - new TheoryData() - { - // Valid objects of different types but not equal - { new Alpha8(.5F), new Argb32(Vector4.Zero), null }, - { new HalfSingle(-1F), new NormalizedShort2(Vector2.Zero), null }, - { new Rgba1010102(Vector4.One), new Bgra5551(Vector4.Zero), null }, - }; - - public static readonly TheoryData NotEqualityData = - new TheoryData() - { - // Valid objects of the same type but not equal - { new Alpha8(.5F), new Alpha8(.8F), typeof(Alpha8) }, - { new Argb32(Vector4.One), new Argb32(Vector4.Zero), typeof(Argb32) }, - { new Bgr565(Vector3.One), new Bgr565(Vector3.Zero), typeof(Bgr565) }, - { new Bgra4444(Vector4.One), new Bgra4444(Vector4.Zero), typeof(Bgra4444) }, - { new Bgra5551(Vector4.One), new Bgra5551(Vector4.Zero), typeof(Bgra5551) }, - { new Byte4(Vector4.One * 255), new Byte4(Vector4.Zero), typeof(Byte4) }, - { new HalfSingle(-1F), new HalfSingle(1F), typeof(HalfSingle) }, - { new HalfVector2(0.1f, -0.3f), new HalfVector2(0.1f, 0.3f), typeof(HalfVector2) }, - { new HalfVector4(Vector4.One), new HalfVector4(Vector4.Zero), typeof(HalfVector4) }, - { new NormalizedByte2(-Vector2.One), new NormalizedByte2(-Vector2.Zero), typeof(NormalizedByte2) }, - { new NormalizedByte4(Vector4.One), new NormalizedByte4(Vector4.Zero), typeof(NormalizedByte4) }, - { new NormalizedShort2(Vector2.One), new NormalizedShort2(Vector2.Zero), typeof(NormalizedShort2) }, - { new NormalizedShort4(Vector4.One), new NormalizedShort4(Vector4.Zero), typeof(NormalizedShort4) }, - { new Rg32(Vector2.One), new Rg32(Vector2.Zero), typeof(Rg32) }, - { new Rgba1010102(Vector4.One), new Rgba1010102(Vector4.Zero), typeof(Rgba1010102) }, - { new Rgba32(Vector4.One), new Rgba32(Vector4.Zero), typeof(Rgba32) }, - { new Rgba64(Vector4.One), new Rgba64(Vector4.Zero), typeof(Rgba64) }, - { new Short2(Vector2.One * 0x7FFF), new Short2(Vector2.Zero), typeof(Short2) }, - { new Short4(Vector4.One * 0x7FFF), new Short4(Vector4.Zero), typeof(Short4) }, - }; - - [Theory] - [MemberData(nameof(EqualityData))] - public void Equality(object first, object second, Type type) - { - // Act - bool equal = first.Equals(second); - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(NotEqualityDataNulls))] - [MemberData(nameof(NotEqualityDataDifferentObjects))] - [MemberData(nameof(NotEqualityData))] - public void NotEquality(object first, object second, Type type) - { - // Act - bool equal = first.Equals(second); - - // Assert - Assert.False(equal); - } - - [Theory] - [MemberData(nameof(EqualityData))] - public void HashCodeEqual(object first, object second, Type type) - { - // Act - bool equal = first.GetHashCode() == second.GetHashCode(); - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(NotEqualityDataDifferentObjects))] - public void HashCodeNotEqual(object first, object second, Type type) - { - // Act - bool equal = first.GetHashCode() == second.GetHashCode(); - - // Assert - Assert.False(equal); - } - - [Theory] - [MemberData(nameof(EqualityData))] - public void EqualityObject(object first, object second, Type type) - { - // Arrange - // Cast to the known object types, this is so that we can hit the - // equality operator on the concrete type, otherwise it goes to the - // default "object" one :) - dynamic firstObject = Convert.ChangeType(first, type); - dynamic secondObject = Convert.ChangeType(second, type); - - // Act - dynamic equal = firstObject.Equals(secondObject); - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(NotEqualityData))] - public void NotEqualityObject(object first, object second, Type type) - { - // Arrange - // Cast to the known object types, this is so that we can hit the - // equality operator on the concrete type, otherwise it goes to the - // default "object" one :) - dynamic firstObject = Convert.ChangeType(first, type); - dynamic secondObject = Convert.ChangeType(second, type); - - // Act - dynamic equal = firstObject.Equals(secondObject); - - // Assert - Assert.False(equal); - } - - [Theory] - [MemberData(nameof(EqualityData))] - public void EqualityOperator(object first, object second, Type type) - { - // Arrange - // Cast to the known object types, this is so that we can hit the - // equality operator on the concrete type, otherwise it goes to the - // default "object" one :) - dynamic firstObject = Convert.ChangeType(first, type); - dynamic secondObject = Convert.ChangeType(second, type); - - // Act - dynamic equal = firstObject == secondObject; - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(NotEqualityData))] - public void NotEqualityOperator(object first, object second, Type type) - { - // Arrange - // Cast to the known object types, this is so that we can hit the - // equality operator on the concrete type, otherwise it goes to the - // default "object" one :) - dynamic firstObject = Convert.ChangeType(first, type); - dynamic secondObject = Convert.ChangeType(second, type); - - // Act - dynamic notEqual = firstObject != secondObject; - - // Assert - Assert.True(notEqual); - } - } -} diff --git a/tests/ImageSharp.Tests/PixelFormats/ColorPackingTests.cs b/tests/ImageSharp.Tests/PixelFormats/ColorPackingTests.cs deleted file mode 100644 index c9a1c8fe7e..0000000000 --- a/tests/ImageSharp.Tests/PixelFormats/ColorPackingTests.cs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Collections.Generic; -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.Colors -{ - public class ColorPackingTests - { - public static IEnumerable Vector4PackData - { - get - { - Vector4[] vector4Values = new Vector4[] - { - Vector4.Zero, - Vector4.One, - Vector4.UnitX, - Vector4.UnitY, - Vector4.UnitZ, - Vector4.UnitW, - }; - - foreach (Vector4 vector4 in vector4Values) - { - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { default(Argb32), vector4Components }; - yield return new object[] { default(Bgra4444), vector4Components }; - yield return new object[] { default(Bgra5551), vector4Components }; - yield return new object[] { default(Byte4), vector4Components }; - yield return new object[] { default(HalfVector4), vector4Components }; - yield return new object[] { default(NormalizedByte4), vector4Components }; - yield return new object[] { default(NormalizedShort4), vector4Components }; - yield return new object[] { default(Rgba1010102), vector4Components }; - yield return new object[] { default(Rgba64), vector4Components }; - yield return new object[] { default(Short4), vector4Components }; - } - } - } - - public static IEnumerable Vector3PackData - { - get - { - Vector4[] vector4Values = new Vector4[] - { - Vector4.One, - new Vector4(0, 0, 0, 1), - new Vector4(1, 0, 0, 1), - new Vector4(0, 1, 0, 1), - new Vector4(0, 0, 1, 1), - }; - - foreach (Vector4 vector4 in vector4Values) - { - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { default(Argb32), vector4Components }; - yield return new object[] { new Bgr565(), vector4Components }; - } - } - } - - [Theory] - [MemberData(nameof(Vector4PackData))] - [MemberData(nameof(Vector3PackData))] - public void FromVector4ToVector4(IPixel packedVector, float[] vector4ComponentsToPack) - { - // Arrange - int precision = 2; - Vector4 vector4ToPack = new Vector4(vector4ComponentsToPack[0], vector4ComponentsToPack[1], vector4ComponentsToPack[2], vector4ComponentsToPack[3]); - packedVector.PackFromVector4(vector4ToPack); - - // Act - Vector4 vector4 = packedVector.ToVector4(); - - // Assert - Assert.Equal(vector4ToPack.X, vector4.X, precision); - Assert.Equal(vector4ToPack.Y, vector4.Y, precision); - Assert.Equal(vector4ToPack.Z, vector4.Z, precision); - Assert.Equal(vector4ToPack.W, vector4.W, precision); - } - } -} diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs new file mode 100644 index 0000000000..db4fa70197 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs @@ -0,0 +1,129 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public class Gray16Tests + { + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(32767)] + [InlineData(42)] + public void Gray16_PackedValue_EqualsInput(ushort input) + => Assert.Equal(input, new Gray16(input).PackedValue); + + [Fact] + public void Gray16_PackFromScaledVector4() + { + // Arrange + Gray16 gray = default; + const ushort expected = 32767; + Vector4 scaled = new Gray16(expected).ToScaledVector4(); + + // Act + gray.PackFromScaledVector4(scaled); + ushort actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(32767)] + public void Gray16_ToScaledVector4(ushort input) + { + // Arrange + var gray = new Gray16(input); + + // Act + Vector4 actual = gray.ToScaledVector4(); + + // Assert + float vectorInput = input / 65535F; + Assert.Equal(vectorInput, actual.X); + Assert.Equal(vectorInput, actual.Y); + Assert.Equal(vectorInput, actual.Z); + Assert.Equal(1F, actual.W); + } + + [Fact] + public void Gray16_PackFromVector4() + { + // Arrange + Gray16 gray = default; + const ushort expected = 32767; + var vector = new Gray16(expected).ToVector4(); + + // Act + gray.PackFromVector4(vector); + ushort actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(32767)] + public void Gray16_ToVector4(ushort input) + { + // Arrange + var gray = new Gray16(input); + + // Act + var actual = gray.ToVector4(); + + // Assert + float vectorInput = input / 65535F; + Assert.Equal(vectorInput, actual.X); + Assert.Equal(vectorInput, actual.Y); + Assert.Equal(vectorInput, actual.Z); + Assert.Equal(1F, actual.W); + } + + [Fact] + public void Gray16_PackFromRgba32() + { + // Arrange + Gray16 gray = default; + const byte rgb = 128; + ushort scaledRgb = ImageMaths.UpscaleFrom8BitTo16Bit(rgb); + ushort expected = ImageMaths.Get16BitBT709Luminance(scaledRgb, scaledRgb, scaledRgb); + + // Act + gray.PackFromRgba32(new Rgba32(rgb, rgb, rgb)); + ushort actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(8100)] + public void Gray16_ToRgba32(ushort input) + { + // Arrange + ushort expected = ImageMaths.DownScaleFrom16BitTo8Bit(input); + var gray = new Gray16(input); + + // Act + var actual = gray.ToRgba32(); + + // Assert + Assert.Equal(expected, actual.R); + Assert.Equal(expected, actual.G); + Assert.Equal(expected, actual.B); + Assert.Equal(byte.MaxValue, actual.A); + } + } +} diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs new file mode 100644 index 0000000000..aaca6c8776 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs @@ -0,0 +1,127 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public class Gray8Tests + { + [Theory] + [InlineData(0)] + [InlineData(255)] + [InlineData(10)] + [InlineData(42)] + public void Gray8_PackedValue_EqualsInput(byte input) + => Assert.Equal(input, new Gray8(input).PackedValue); + + [Fact] + public void Gray8_PackFromScaledVector4() + { + // Arrange + Gray8 gray = default; + const byte expected = 128; + Vector4 scaled = new Gray8(expected).ToScaledVector4(); + + // Act + gray.PackFromScaledVector4(scaled); + byte actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0)] + [InlineData(255)] + [InlineData(30)] + public void Gray8_ToScaledVector4(byte input) + { + // Arrange + var gray = new Gray8(input); + + // Act + Vector4 actual = gray.ToScaledVector4(); + + // Assert + float scaledInput = input / 255F; + Assert.Equal(scaledInput, actual.X); + Assert.Equal(scaledInput, actual.Y); + Assert.Equal(scaledInput, actual.Z); + Assert.Equal(1, actual.W); + } + + [Fact] + public void Gray8_PackFromVector4() + { + // Arrange + Gray8 gray = default; + const int expected = 128; + var vector = new Gray8(expected).ToVector4(); + + // Act + gray.PackFromVector4(vector); + byte actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0)] + [InlineData(255)] + [InlineData(30)] + public void Gray8_ToVector4(byte input) + { + // Arrange + var gray = new Gray8(input); + + // Act + var actual = gray.ToVector4(); + + // Assert + float scaledInput = input / 255F; + Assert.Equal(scaledInput, actual.X); + Assert.Equal(scaledInput, actual.Y); + Assert.Equal(scaledInput, actual.Z); + Assert.Equal(1, actual.W); + } + + [Fact] + public void Gray8_PackFromRgba32() + { + // Arrange + Gray8 gray = default; + const byte rgb = 128; + byte expected = ImageMaths.Get8BitBT709Luminance(rgb, rgb, rgb); + + // Act + gray.PackFromRgba32(new Rgba32(rgb, rgb, rgb)); + byte actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0)] + [InlineData(255)] + [InlineData(30)] + public void Gray8_ToRgba32(byte input) + { + // Arrange + var gray = new Gray8(input); + + // Act + var actual = gray.ToRgba32(); + + // Assert + Assert.Equal(input, actual.R); + Assert.Equal(input, actual.G); + Assert.Equal(input, actual.B); + Assert.Equal(byte.MaxValue, actual.A); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs index 3376645f34..fed55af6f7 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs @@ -66,112 +66,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - [Fact] - public void HalfSingle_ToRgb24() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Rgb24); - var expected = new Rgb24(128, 0, 0); - - // act - halfVector.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_Rgba32() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Rgba32); - var expected = new Rgba32(128, 0, 0, 255); - - // act - halfVector.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_ToBgr24() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Bgr24); - var expected = new Bgr24(128, 0, 0); - - // act - halfVector.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_Bgra32() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Bgra32); - var expected = new Bgra32(128, 0, 0, 255); - - // act - halfVector.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_Argb32() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Argb32); - var expected = new Argb32(128, 0, 0, 255); - - // act - halfVector.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(HalfSingle); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(HalfSingle); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs index c2a524f0dc..c775e3a0de 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs @@ -71,112 +71,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - [Fact] - public void HalfVector2_ToRgb24() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Rgb24); - var expected = new Rgb24(128, 64, 0); - - // act - halfVector.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_Rgba32() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Rgba32); - var expected = new Rgba32(128, 64, 0, 255); - - // act - halfVector.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_ToBgr24() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Bgr24); - var expected = new Bgr24(128, 64, 0); - - // act - halfVector.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_Bgra32() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Bgra32); - var expected = new Bgra32(128, 64, 0, 255); - - // act - halfVector.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_Argb32() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Argb32); - var expected = new Argb32(128, 64, 0, 255); - - // act - halfVector.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(HalfVector2); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(HalfVector2); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs index 8b28dd8277..540a1ed08b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs @@ -65,160 +65,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - [Fact] - public void HalfVector4_ToRgb24() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Rgb24); - var expected = new Rgb24(64, 128, 191); - - // act - halfVector.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_Rgba32() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Rgba32); - var expected = new Rgba32(64, 128, 191, 255); - - // act - halfVector.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_ToBgr24() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Bgr24); - var expected = new Bgr24(64, 128, 191); - - // act - halfVector.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_Bgra32() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Bgra32); - var expected = new Bgra32(64, 128, 191, 255); - - // act - halfVector.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_Argb32() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Argb32); - var expected = new Argb32(64, 128, 191, 255); - - // act - halfVector.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromRgba32_ToRgba32() - { - // arrange - var halVector = default(HalfVector4); - var actual = default(Rgba32); - var expected = new Rgba32(64, 128, 191, 255); - - // act - halVector.PackFromRgba32(expected); - halVector.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromBgra32_ToBgra32() - { - // arrange - var halVector = default(HalfVector4); - var actual = default(Bgra32); - var expected = new Bgra32(64, 128, 191, 255); - - // act - halVector.PackFromBgra32(expected); - halVector.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromArgb32_ToArgb32() - { - // arrange - var halVector = default(HalfVector4); - var actual = default(Argb32); - var expected = new Argb32(64, 128, 191, 255); - - // act - halVector.PackFromArgb32(expected); - halVector.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(HalfVector4); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(HalfVector4); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs index 83f22e2aa0..98b747a94f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs @@ -66,128 +66,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - [Fact] - public void NormalizedByte2_PackFromRgba32() - { - // arrange - var byte2 = new NormalizedByte2(); - var rgba = new Rgba32(141, 90, 0, 0); - int expected = 0xda0d; - - // act - byte2.PackFromRgba32(rgba); - ushort actual = byte2.PackedValue; - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToRgb24() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Rgb24); - var expected = new Rgb24(141, 90, 0); - - // act - short4.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToRgba32() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Rgba32); - var expected = new Rgba32(141, 90, 0, 255); - - // act - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToBgr24() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Bgr24); - var expected = new Bgr24(141, 90, 0); - - // act - short4.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToBgra32() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Bgra32); - var expected = new Bgra32(141, 90, 0, 255); - - // act - short4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToArgb32() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Argb32); - var expected = new Argb32(141, 90, 0, 255); - - // act - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(NormalizedByte2); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(NormalizedByte2); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs index 16516496f8..d9cca360b2 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs @@ -60,145 +60,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - [Fact] - public void NormalizedByte4_ToRgb24() - { - // arrange - var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(141, 90, 192); - - // act - short4.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_ToRgba32() - { - // arrange - var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(141, 90, 192, 39); - - // act - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_ToBgr24() - { - // arrange - var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(141, 90, 192); - - // act - short4.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_ToArgb32() - { - // arrange - var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(141, 90, 192, 39); - - // act - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromRgba32_ToRgba32() - { - // arrange - var short4 = default(NormalizedByte4); - var actual = default(Rgba32); - var expected = new Rgba32(9, 115, 202, 127); - - // act - short4.PackFromRgba32(new Rgba32(9, 115, 202, 127)); - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromBgra32_ToRgba32() - { - // arrange - var actual = default(Bgra32); - var short4 = default(NormalizedByte4); - var expected = new Bgra32(9, 115, 202, 127); - - // act - short4.PackFromBgra32(expected); - short4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromArgb32_ToRgba32() - { - // arrange - var short4 = default(NormalizedByte4); - var actual = default(Argb32); - var expected = new Argb32(9, 115, 202, 127); - - // act - short4.PackFromArgb32(expected); - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(NormalizedByte4); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(NormalizedByte4); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs index 2fb7f05aca..83eab82ac8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs @@ -69,129 +69,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - [Fact] - public void NormalizedShort2_PackFromRgba32_ToRgb24() - { - // arrange - var actual = default(Rgb24); - var short2 = new NormalizedShort2(); - var rgba = new Rgba32(141, 90, 0, 0); - var expected = new Rgb24(141, 90, 0); - - // act - short2.PackFromRgba32(rgba); - short2.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToRgb24() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Rgb24); - var expected = new Rgb24(141, 90, 0); - - // act - short2.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToRgba32() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Rgba32); - var expected = new Rgba32(141, 90, 0, 255); - - // act - short2.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToBgr24() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Bgr24); - var expected = new Bgr24(141, 90, 0); - - // act - short2.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToBgra32() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Bgra32); - var expected = new Bgra32(141, 90, 0, 255); - - // act - short2.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToArgb32() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Argb32); - var expected = new Argb32(141, 90, 0, 255); - - // act - short2.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(NormalizedShort2); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(NormalizedShort2); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs index 7dcdd9c88b..40b2d05e31 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // arrange var pixel = default(NormalizedShort4); Vector4 scaled = new NormalizedShort4(Vector4.One).ToScaledVector4(); - ulong expected = (ulong)0x7FFF7FFF7FFF7FFF; + ulong expected = 0x7FFF7FFF7FFF7FFF; // act pixel.PackFromScaledVector4(scaled); @@ -61,145 +61,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - [Fact] - public void NormalizedShort4_ToRgb24() - { - // arrange - var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(141, 90, 192); - - // act - short4.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_ToRgba32() - { - // arrange - var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(141, 90, 192, 39); - - // act - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_ToBgr24() - { - // arrange - var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(141, 90, 192); - - // act - short4.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_ToArgb32() - { - // arrange - var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(141, 90, 192, 39); - - // act - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromRgba32_ToRgba32() - { - // arrange - var short4 = default(NormalizedShort4); - var expected = new Rgba32(9, 115, 202, 127); - var actual = default(Rgba32); - - // act - short4.PackFromRgba32(expected); - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromBgra32_ToRgba32() - { - // arrange - var short4 = default(NormalizedShort4); - var actual = default(Bgra32); - var expected = new Bgra32(9, 115, 202, 127); - - // act - short4.PackFromBgra32(expected); - short4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromArgb32_ToRgba32() - { - // arrange - var short4 = default(NormalizedShort4); - var actual = default(Argb32); - var expected = new Argb32(9, 115, 202, 127); - - // act - short4.PackFromArgb32(expected); - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(NormalizedShort4); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(NormalizedShort4); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 9e41fd94f3..8a0aee1a7c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -13,92 +13,313 @@ using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests.PixelFormats { - public partial class PixelOperationsTests + public class PixelOperationsTests { - public class Rgba32 : PixelOperationsTests + public const string SkipProfilingBenchmarks = +#if true + "Profiling benchmark - enable manually!"; +#else + null; +#endif + + public class Argb32OperationsTests : PixelOperationsTests { - public Rgba32(ITestOutputHelper output) + + public Argb32OperationsTests(ITestOutputHelper output) : base(output) { } - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + + public class Bgr24OperationsTests : PixelOperationsTests + { + public Bgr24OperationsTests(ITestOutputHelper output) + : base(output) + { + } [Fact] - public void IsSpecialImplementation() + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + + public class Bgra32OperationsTests : PixelOperationsTests + { + public Bgra32OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + + public class Gray8OperationsTests : PixelOperationsTests + { + public Gray8OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromGray8Bytes(int count) + { + byte[] source = CreateByteTestData(count); + var expected = new Gray8[count]; + + for (int i = 0; i < count; i++) + { + expected[i].PackFromGray8(new Gray8(source[i])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromGray8Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray8Bytes(int count) + { + Gray8[] source = CreatePixelTestData(count); + byte[] expected = new byte[count]; + var gray = default(Gray8); + + for (int i = 0; i < count; i++) + { + gray.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i] = gray.PackedValue; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray8Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromGray16Bytes(int count) + { + byte[] source = CreateByteTestData(count * 2); + Span sourceSpan = source.AsSpan(); + var expected = new Gray8[count]; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + expected[i].PackFromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromGray16Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray16Bytes(int count) + { + Gray8[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 2]; + Gray16 gray = default; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + gray.PackFromScaledVector4(source[i].ToScaledVector4()); + OctetBytes bytes = Unsafe.As(ref gray); + expected[i2] = bytes[0]; + expected[i2 + 1] = bytes[1]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray16Bytes(s, d.GetSpan(), count) + ); + } + } + + public class Gray16OperationsTests : PixelOperationsTests + { + public Gray16OperationsTests(ITestOutputHelper output) + : base(output) { - Assert.IsType(PixelOperations.Instance); } [Fact] - public void ToVector4SimdAligned() + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromGray8Bytes(int count) { - if (!Vector.IsHardwareAccelerated) + byte[] source = CreateByteTestData(count); + var expected = new Gray16[count]; + + for (int i = 0; i < count; i++) { - return; + expected[i].PackFromGray8(new Gray8(source[i])); } - ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(64); - Vector4[] expected = CreateExpectedVector4Data(source); + TestOperation( + source, + expected, + (s, d) => Operations.PackFromGray8Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray8Bytes(int count) + { + Gray16[] source = CreatePixelTestData(count); + byte[] expected = new byte[count]; + var gray = default(Gray8); + + for (int i = 0; i < count; i++) + { + gray.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i] = gray.PackedValue; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray8Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromGray16Bytes(int count) + { + byte[] source = CreateByteTestData(count * 2); + Span sourceSpan = source.AsSpan(); + var expected = new Gray16[count]; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + expected[i].PackFromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromGray16Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray16Bytes(int count) + { + Gray16[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 2]; + Gray16 gray = default; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + gray.PackFromScaledVector4(source[i].ToScaledVector4()); + OctetBytes bytes = Unsafe.As(ref gray); + expected[i2] = bytes[0]; + expected[i2 + 1] = bytes[1]; + } TestOperation( source, expected, - (s, d) => ImageSharp.PixelFormats.Rgba32.PixelOperations.ToVector4SimdAligned(s, d.GetSpan(), 64) + (s, d) => Operations.ToGray16Bytes(s, d.GetSpan(), count) ); } + } + public class Rgba32OperationsTests : PixelOperationsTests + { + public Rgba32OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - // [Fact] // Profiling benchmark - enable manually! -#pragma warning disable xUnit1013 // Public method should be marked as test + [Fact(Skip = SkipProfilingBenchmarks)] public void Benchmark_ToVector4() -#pragma warning restore xUnit1013 // Public method should be marked as test { - int times = 200000; - int count = 1024; + const int times = 200000; + const int count = 1024; - using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) + using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) { this.Measure( times, - () => - { - PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan(), count); - }); + () => PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan(), count)); } } } - public class Argb32 : PixelOperationsTests + public class Rgb48OperationsTests : PixelOperationsTests { - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public Argb32(ITestOutputHelper output) + public Rgb48OperationsTests(ITestOutputHelper output) : base(output) { } - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + + public class Rgba64OperationsTests : PixelOperationsTests + { + public Rgba64OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + + public class RgbaVectorOperationsTests : PixelOperationsTests + { + public RgbaVectorOperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); } [Theory] [WithBlankImages(1, 1, PixelTypes.All)] - public void GetGlobalInstance(TestImageProvider dummy) - where TPixel : struct, IPixel - { - Assert.NotNull(PixelOperations.Instance); - } - - [Fact] - public void IsOpaqueColor() - { - Assert.True(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); - - Assert.False(new GraphicsOptions(true, 0.5f).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); - Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Transparent)); - Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); - Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal,PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); + public void GetGlobalInstance(TestImageProvider _) + where TPixel : struct, IPixel => Assert.NotNull(PixelOperations.Instance); + + [Fact] + public void IsOpaqueColor() + { + Assert.True(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true, 0.5f).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Transparent)); + Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); } } @@ -110,9 +331,9 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { } - public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + public static TheoryData ArraySizesData => new TheoryData { 0, 1, 2, 7, 16, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 1111 }; - private static PixelOperations Operations => PixelOperations.Instance; + internal static PixelOperations Operations => PixelOperations.Instance; internal static TPixel[] CreateExpectedPixelData(Vector4[] source) { @@ -216,385 +437,333 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgb24Bytes(int count) + public void PackFromArgb32Bytes(int count) { - byte[] source = CreateByteTestData(count * 3); + byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i3 = i * 3; + int i4 = i * 4; - expected[i].PackFromRgba32(new Rgba32(source[i3 + 0], source[i3 + 1], source[i3 + 2], 255)); + expected[i].PackFromArgb32(new Argb32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); } TestOperation( source, expected, - (s, d) => Operations.PackFromRgb24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromArgb32Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToRgb24Bytes(int count) + public void ToArgb32Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 3]; - var rgb = default(Rgb24); + byte[] expected = new byte[count * 4]; + var argb = default(Argb32); for (int i = 0; i < count; i++) { - int i3 = i * 3; - source[i].ToRgb24(ref rgb); - expected[i3] = rgb.R; - expected[i3 + 1] = rgb.G; - expected[i3 + 2] = rgb.B; + int i4 = i * 4; + argb.PackFromScaledVector4(source[i].ToScaledVector4()); + + expected[i4] = argb.A; + expected[i4 + 1] = argb.R; + expected[i4 + 2] = argb.G; + expected[i4 + 3] = argb.B; } TestOperation( source, expected, - (s, d) => Operations.ToRgb24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToArgb32Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgba32Bytes(int count) + public void PackFromBgr24Bytes(int count) { - byte[] source = CreateByteTestData(count * 4); + byte[] source = CreateByteTestData(count * 3); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i4 = i * 4; + int i3 = i * 3; - expected[i].PackFromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); + expected[i].PackFromBgr24(new Bgr24(source[i3 + 2], source[i3 + 1], source[i3])); } TestOperation( source, expected, - (s, d) => Operations.PackFromRgba32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromBgr24Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToRgba32Bytes(int count) + public void ToBgr24Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var rgba = default(Rgba32); + byte[] expected = new byte[count * 3]; + var bgr = default(Bgr24); for (int i = 0; i < count; i++) { - int i4 = i * 4; - source[i].ToRgba32(ref rgba); - expected[i4] = rgba.R; - expected[i4 + 1] = rgba.G; - expected[i4 + 2] = rgba.B; - expected[i4 + 3] = rgba.A; + int i3 = i * 3; + bgr.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i3] = bgr.B; + expected[i3 + 1] = bgr.G; + expected[i3 + 2] = bgr.R; } TestOperation( source, expected, - (s, d) => Operations.ToRgba32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToBgr24Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgb48Bytes(int count) + public void PackFromBgra32Bytes(int count) { - byte[] source = CreateByteTestData(count * 6); - Span sourceSpan = source.AsSpan(); + byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; - var rgba64 = new Rgba64(0, 0, 0, 65535); for (int i = 0; i < count; i++) { - int i6 = i * 6; - rgba64.Rgb = MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]; - expected[i].PackFromRgba64(rgba64); + int i4 = i * 4; + + expected[i].PackFromBgra32(new Bgra32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); } TestOperation( source, expected, - (s, d) => Operations.PackFromRgb48Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromBgra32Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToRgb48Bytes(int count) + public void ToBgra32Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 6]; - Rgb48 rgb = default; + byte[] expected = new byte[count * 4]; + var bgra = default(Bgra32); for (int i = 0; i < count; i++) { - int i6 = i * 6; - source[i].ToRgb48(ref rgb); - Rgba64Bytes rgb48Bytes = Unsafe.As(ref rgb); - expected[i6] = rgb48Bytes[0]; - expected[i6 + 1] = rgb48Bytes[1]; - expected[i6 + 2] = rgb48Bytes[2]; - expected[i6 + 3] = rgb48Bytes[3]; - expected[i6 + 4] = rgb48Bytes[4]; - expected[i6 + 5] = rgb48Bytes[5]; + int i4 = i * 4; + bgra.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i4] = bgra.B; + expected[i4 + 1] = bgra.G; + expected[i4 + 2] = bgra.R; + expected[i4 + 3] = bgra.A; } TestOperation( source, expected, - (s, d) => Operations.ToRgb48Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToBgra32Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgba64Bytes(int count) + public void PackFromRgb24Bytes(int count) { - byte[] source = CreateByteTestData(count * 8); - Span sourceSpan = source.AsSpan(); + byte[] source = CreateByteTestData(count * 3); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i8 = i * 8; - expected[i].PackFromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); + int i3 = i * 3; + + expected[i].PackFromRgb24(new Rgb24(source[i3 + 0], source[i3 + 1], source[i3 + 2])); } TestOperation( source, expected, - (s, d) => Operations.PackFromRgba64Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromRgb24Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToRgba64Bytes(int count) + public void ToRgb24Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 8]; - Rgba64 rgba = default; + byte[] expected = new byte[count * 3]; + var rgb = default(Rgb24); for (int i = 0; i < count; i++) { - int i8 = i * 8; - source[i].ToRgba64(ref rgba); - Rgba64Bytes rgba64Bytes = Unsafe.As(ref rgba); - expected[i8] = rgba64Bytes[0]; - expected[i8 + 1] = rgba64Bytes[1]; - expected[i8 + 2] = rgba64Bytes[2]; - expected[i8 + 3] = rgba64Bytes[3]; - expected[i8 + 4] = rgba64Bytes[4]; - expected[i8 + 5] = rgba64Bytes[5]; - expected[i8 + 6] = rgba64Bytes[6]; - expected[i8 + 7] = rgba64Bytes[7]; + int i3 = i * 3; + rgb.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i3] = rgb.R; + expected[i3 + 1] = rgb.G; + expected[i3 + 2] = rgb.B; } TestOperation( source, expected, - (s, d) => Operations.ToRgba64Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgb24Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromBgr24Bytes(int count) + public void PackFromRgba32Bytes(int count) { - byte[] source = CreateByteTestData(count * 3); + byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i3 = i * 3; + int i4 = i * 4; - expected[i].PackFromRgba32(new Rgba32(source[i3 + 2], source[i3 + 1], source[i3 + 0], 255)); + expected[i].PackFromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); } TestOperation( source, expected, - (s, d) => Operations.PackFromBgr24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromRgba32Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToBgr24Bytes(int count) + public void ToRgba32Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 3]; - var bgr = default(Bgr24); + byte[] expected = new byte[count * 4]; + var rgba = default(Rgba32); for (int i = 0; i < count; i++) { - int i3 = i * 3; - source[i].ToBgr24(ref bgr); - expected[i3] = bgr.B; - expected[i3 + 1] = bgr.G; - expected[i3 + 2] = bgr.R; + int i4 = i * 4; + rgba.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i4] = rgba.R; + expected[i4 + 1] = rgba.G; + expected[i4 + 2] = rgba.B; + expected[i4 + 3] = rgba.A; } TestOperation( source, expected, - (s, d) => Operations.ToBgr24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgba32Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromBgra32Bytes(int count) + public void PackFromRgb48Bytes(int count) { - byte[] source = CreateByteTestData(count * 4); + byte[] source = CreateByteTestData(count * 6); + Span sourceSpan = source.AsSpan(); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); + int i6 = i * 6; + expected[i].PackFromRgb48(MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]); } TestOperation( source, expected, - (s, d) => Operations.PackFromBgra32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromRgb48Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToZyxwBytes(int count) + public void ToRgb48Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var bgra = default(Bgra32); + byte[] expected = new byte[count * 6]; + Rgb48 rgb = default; for (int i = 0; i < count; i++) { - int i4 = i * 4; - source[i].ToBgra32(ref bgra); - expected[i4] = bgra.B; - expected[i4 + 1] = bgra.G; - expected[i4 + 2] = bgra.R; - expected[i4 + 3] = bgra.A; + int i6 = i * 6; + rgb.PackFromScaledVector4(source[i].ToScaledVector4()); + OctetBytes rgb48Bytes = Unsafe.As(ref rgb); + expected[i6] = rgb48Bytes[0]; + expected[i6 + 1] = rgb48Bytes[1]; + expected[i6 + 2] = rgb48Bytes[2]; + expected[i6 + 3] = rgb48Bytes[3]; + expected[i6 + 4] = rgb48Bytes[4]; + expected[i6 + 5] = rgb48Bytes[5]; } TestOperation( source, expected, - (s, d) => Operations.ToBgra32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgb48Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromArgb32Bytes(int count) + public void PackFromRgba64Bytes(int count) { - byte[] source = CreateByteTestData(count * 4); + byte[] source = CreateByteTestData(count * 8); + Span sourceSpan = source.AsSpan(); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); + int i8 = i * 8; + expected[i].PackFromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); } TestOperation( source, expected, - (s, d) => Operations.PackFromArgb32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromRgba64Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToArgb32Bytes(int count) + public void ToRgba64Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var argb = default(Argb32); + byte[] expected = new byte[count * 8]; + Rgba64 rgba = default; for (int i = 0; i < count; i++) { - int i4 = i * 4; - source[i].ToArgb32(ref argb); - expected[i4] = argb.A; - expected[i4 + 1] = argb.R; - expected[i4 + 2] = argb.G; - expected[i4 + 3] = argb.B; + int i8 = i * 8; + rgba.PackFromScaledVector4(source[i].ToScaledVector4()); + OctetBytes rgba64Bytes = Unsafe.As(ref rgba); + expected[i8] = rgba64Bytes[0]; + expected[i8 + 1] = rgba64Bytes[1]; + expected[i8 + 2] = rgba64Bytes[2]; + expected[i8 + 3] = rgba64Bytes[3]; + expected[i8 + 4] = rgba64Bytes[4]; + expected[i8 + 5] = rgba64Bytes[5]; + expected[i8 + 6] = rgba64Bytes[6]; + expected[i8 + 7] = rgba64Bytes[7]; } TestOperation( source, expected, - (s, d) => Operations.ToArgb32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgba64Bytes(s, d.GetSpan(), count) ); } - private class TestBuffers : IDisposable - where TSource : struct - where TDest : struct - { - public TSource[] SourceBuffer { get; } - public IMemoryOwner ActualDestBuffer { get; } - public TDest[] ExpectedDestBuffer { get; } - - public TestBuffers(TSource[] source, TDest[] expectedDest) - { - this.SourceBuffer = source; - this.ExpectedDestBuffer = expectedDest; - this.ActualDestBuffer = Configuration.Default.MemoryAllocator.Allocate(expectedDest.Length); - } - - public void Dispose() - { - this.ActualDestBuffer.Dispose(); - } - - private const float Tolerance = 0.0001f; - - public void Verify() - { - int count = this.ExpectedDestBuffer.Length; - - if (typeof(TDest) == typeof(Vector4)) - { - - Span expected = MemoryMarshal.Cast(this.ExpectedDestBuffer.AsSpan()); - Span actual = MemoryMarshal.Cast(this.ActualDestBuffer.GetSpan()); - - for (int i = 0; i < count; i++) - { - // ReSharper disable PossibleNullReferenceException - Assert.Equal(expected[i], actual[i], new ApproximateFloatComparer(0.001f)); - // ReSharper restore PossibleNullReferenceException - } - } - else - { - Span expected = this.ExpectedDestBuffer.AsSpan(); - Span actual = this.ActualDestBuffer.GetSpan(); - for (int i = 0; i < count; i++) - { - Assert.Equal(expected[i], actual[i]); - } - } - } - } - internal static void TestOperation( TSource[] source, TDest[] expected, @@ -674,7 +843,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [StructLayout(LayoutKind.Sequential)] - private unsafe struct Rgba64Bytes + internal unsafe struct OctetBytes { public fixed byte Data[8]; @@ -683,10 +852,56 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - ref byte self = ref Unsafe.As(ref this); + ref byte self = ref Unsafe.As(ref this); return Unsafe.Add(ref self, idx); } } } + + private class TestBuffers : IDisposable + where TSource : struct + where TDest : struct + { + public TSource[] SourceBuffer { get; } + public IMemoryOwner ActualDestBuffer { get; } + public TDest[] ExpectedDestBuffer { get; } + + public TestBuffers(TSource[] source, TDest[] expectedDest) + { + this.SourceBuffer = source; + this.ExpectedDestBuffer = expectedDest; + this.ActualDestBuffer = Configuration.Default.MemoryAllocator.Allocate(expectedDest.Length); + } + + public void Dispose() => this.ActualDestBuffer.Dispose(); + + public void Verify() + { + int count = this.ExpectedDestBuffer.Length; + + if (typeof(TDest) == typeof(Vector4)) + { + Span expected = MemoryMarshal.Cast(this.ExpectedDestBuffer.AsSpan()); + Span actual = MemoryMarshal.Cast(this.ActualDestBuffer.GetSpan()); + + var comparer = new ApproximateFloatComparer(0.001f); + for (int i = 0; i < count; i++) + { + // ReSharper disable PossibleNullReferenceException + Assert.Equal(expected[i], actual[i], comparer); + // ReSharper restore PossibleNullReferenceException + } + } + else + { + Span expected = this.ExpectedDestBuffer.AsSpan(); + Span actual = this.ActualDestBuffer.GetSpan(); + for (int i = 0; i < count; i++) + { + Assert.Equal(expected[i], actual[i]); + } + } + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs index 3a80c3436d..135843e35f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs @@ -68,97 +68,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector2.Zero, new Rg32(Vector2.One * -1234.0f).ToVector2()); Assert.Equal(Vector2.One, new Rg32(Vector2.One * 1234.0f).ToVector2()); } - - [Fact] - public void Rg32_ToRgb24() - { - // arrange - var rg32 = new Rg32(0.1f, -0.3f); - var actual = default(Rgb24); - var expected = new Rgb24(25, 0, 0); - - // act - rg32.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_ToRgba32() - { - // arrange - var rg32 = new Rg32(0.1f, -0.3f); - var actual = default(Rgba32); - var expected = new Rgba32(25, 0, 0, 255); - - // act - rg32.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_ToBgr24() - { - // arrange - var rg32 = new Rg32(0.1f, -0.3f); - var actual = default(Bgr24); - var expected = new Bgr24(25, 0, 0); - - // act - rg32.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_ToArgb32() - { - // arrange - var rg32 = new Rg32(0.1f, -0.3f); - var actual = default(Argb32); - var expected = new Argb32(25, 0, 0, 255); - - // act - rg32.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rg32); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rg32); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index d056bf30d2..aa6d9024cd 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using SixLabors.ImageSharp.PixelFormats; using Xunit; @@ -11,7 +10,12 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public class Rgb24Tests { public static readonly TheoryData ColorData = - new TheoryData() { { 1, 2, 3 }, { 4, 5, 6 }, { 0, 255, 42 } }; + new TheoryData() + { + { 1, 2, 3 }, + { 4, 5, 6 }, + { 0, 255, 42 } + }; [Theory] [MemberData(nameof(ColorData))] @@ -96,80 +100,13 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); } - [Fact] - public void ToRgb24() - { - var rgb = new Rgb24(1, 2, 3); - var dest = default(Rgb24); - - rgb.ToRgb24(ref dest); - - Assert.Equal(rgb, dest); - } - [Fact] public void ToRgba32() { var rgb = new Rgb24(1, 2, 3); - var rgba = default(Rgba32); - - rgb.ToRgba32(ref rgba); + var rgba = rgb.ToRgba32(); Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); } - - [Fact] - public void ToBgr24() - { - var rgb = new Rgb24(1, 2, 3); - var bgr = default(Bgr24); - - rgb.ToBgr24(ref bgr); - - Assert.Equal(new Bgr24(1, 2, 3), bgr); - } - - [Fact] - public void ToBgra32() - { - var rgb = new Rgb24(1, 2, 3); - var bgra = default(Bgra32); - - rgb.ToBgra32(ref bgra); - - Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); - } - - [Fact] - public void Rgb24_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rgb24); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb24_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rgb24); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index 77d6544f00..16dfd7f577 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -18,45 +18,23 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(9830, rgb.G); Assert.Equal(19660, rgb.B); Assert.Equal(29491, rgb.A); - - rgb = new Rgba64(5243 / 65535F, 9830 / 65535F, 19660 / 65535F, 29491 / 65535F); - - Assert.Equal(5243, rgb.R); - Assert.Equal(9830, rgb.G); - Assert.Equal(19660, rgb.B); - Assert.Equal(29491, rgb.A); } [Fact] public void Rgb48_ToVector4() - { - Assert.Equal(new Vector4(0, 0, 0, 1), new Rgb48(Vector3.Zero).ToVector4()); - Assert.Equal(Vector4.One, new Rgb48(Vector3.One).ToVector4()); - } + => Assert.Equal(Vector4.One, new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue).ToVector4()); [Fact] public void Rgb48_ToScaledVector4() - { - // arrange - var short2 = new Rgb48(Vector3.One); - - // act - Vector4 actual = short2.ToScaledVector4(); - - // assert - Assert.Equal(1, actual.X); - Assert.Equal(1, actual.Y); - Assert.Equal(1, actual.Z); - Assert.Equal(1, actual.W); - } + => Assert.Equal(Vector4.One, new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue).ToVector4()); [Fact] public void Rgb48_PackFromScaledVector4() { // arrange var pixel = default(Rgb48); - var short3 = new Rgb48(Vector3.One); - var expected = new Rgb48(Vector3.One); + var short3 = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); + var expected = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); // act Vector4 scaled = short3.ToScaledVector4(); @@ -66,134 +44,18 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, pixel); } - [Fact] - public void Rgb48_Clamping() - { - Assert.Equal(new Vector4(0, 0, 0, 1), new Rgb48(Vector3.One * -1234.0f).ToVector4()); - Assert.Equal(Vector4.One, new Rgb48(Vector3.One * 1234.0f).ToVector4()); - } - - [Fact] - public void Rgb48_ToRgb24() - { - // arrange - var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Rgb24); - var expected = new Rgb24(20, 38, 76); - - // act - rgba48.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - [Fact] public void Rgb48_ToRgba32() { // arrange - var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 76, 255); - - // act - rgba48.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_ToArgb32() - { - // arrange - var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Argb32); - var expected = new Argb32(20, 38, 76, 255); - - // act - rgba48.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_ToBgr24() - { - // arrange - var rgb48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Bgr24); - var expected = new Bgr24(20, 38, 76); - - // act - rgb48.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_ToBgra32() - { - // arrange - var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Bgra32); - var expected = new Bgra32(20, 38, 76, 255); - - // act - rgba48.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_PackFromRgba32_ToRgba32() - { - // arrange - var rgb48 = default(Rgb48); - var actual = default(Rgba32); + var rgba48 = new Rgb48(5140, 9766, 19532); var expected = new Rgba32(20, 38, 76, 255); - // act - rgb48.PackFromRgba32(expected); - rgb48.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rgb48); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rgb48); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); + var actual = rgba48.ToRgba32(); // assert Assert.Equal(expected, actual); } } -} +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index fcb3b6c7c8..243d4a44c9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -71,141 +71,15 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One, new Rgba1010102(Vector4.One * 1234.0f).ToVector4()); } - [Fact] - public void Rgba1010102_ToRgb24() - { - // arrange - var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(25, 0, 128); - - // act - rgba.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - [Fact] public void Rgba1010102_ToRgba32() { // arrange var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(25, 0, 128, 0); - - // act - rgba.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_ToBgr24() - { - // arrange - var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(25, 0, 128); - - // act - rgba.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_ToBgra32() - { - // arrange - var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(25, 0, 128, 0); - - // act - rgba.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromRgba32_ToRgba32() - { - // arrange - var rgba = default(Rgba1010102); var expected = new Rgba32(25, 0, 128, 0); - var actual = default(Rgba32); - - // act - rgba.PackFromRgba32(expected); - rgba.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromBgra32_ToBgra32() - { - // arrange - var rgba = default(Rgba1010102); - var expected = new Bgra32(25, 0, 128, 0); - var actual = default(Bgra32); - - // act - rgba.PackFromBgra32(expected); - rgba.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromArgb32_ToArgb32() - { - // arrange - var rgba = default(Rgba1010102); - var expected = new Argb32(25, 0, 128, 0); - var actual = default(Argb32); - - // act - rgba.PackFromArgb32(expected); - rgba.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rgba1010102); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rgba1010102); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); + var actual = rgba.ToRgba32(); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index 4b2c187765..30a5f961b7 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -19,12 +19,12 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void AreEqual() { - Rgba32 color1 = new Rgba32(0, 0, 0); - Rgba32 color2 = new Rgba32(0, 0, 0, 1F); - Rgba32 color3 = Rgba32.FromHex("#000"); - Rgba32 color4 = Rgba32.FromHex("#000F"); - Rgba32 color5 = Rgba32.FromHex("#000000"); - Rgba32 color6 = Rgba32.FromHex("#000000FF"); + var color1 = new Rgba32(0, 0, 0); + var color2 = new Rgba32(0, 0, 0, 1F); + var color3 = Rgba32.FromHex("#000"); + var color4 = Rgba32.FromHex("#000F"); + var color5 = Rgba32.FromHex("#000000"); + var color6 = Rgba32.FromHex("#000000FF"); Assert.Equal(color1, color2); Assert.Equal(color1, color3); @@ -39,11 +39,11 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void AreNotEqual() { - Rgba32 color1 = new Rgba32(255, 0, 0, 255); - Rgba32 color2 = new Rgba32(0, 0, 0, 255); - Rgba32 color3 = Rgba32.FromHex("#000"); - Rgba32 color4 = Rgba32.FromHex("#000000"); - Rgba32 color5 = Rgba32.FromHex("#FF000000"); + var color1 = new Rgba32(255, 0, 0, 255); + var color2 = new Rgba32(0, 0, 0, 255); + var color3 = Rgba32.FromHex("#000"); + var color4 = Rgba32.FromHex("#000000"); + var color5 = Rgba32.FromHex("#FF000000"); Assert.NotEqual(color1, color2); Assert.NotEqual(color1, color3); @@ -57,25 +57,25 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void ConstructorAssignsProperties() { - Rgba32 color1 = new Rgba32(1, .1f, .133f, .864f); + var color1 = new Rgba32(1, .1f, .133f, .864f); Assert.Equal(255, color1.R); Assert.Equal((byte)Math.Round(.1f * 255), color1.G); Assert.Equal((byte)Math.Round(.133f * 255), color1.B); Assert.Equal((byte)Math.Round(.864f * 255), color1.A); - Rgba32 color2 = new Rgba32(1, .1f, .133f); + var color2 = new Rgba32(1, .1f, .133f); Assert.Equal(255, color2.R); Assert.Equal(Math.Round(.1f * 255), color2.G); Assert.Equal(Math.Round(.133f * 255), color2.B); Assert.Equal(255, color2.A); - Rgba32 color4 = new Rgba32(new Vector3(1, .1f, .133f)); + var color4 = new Rgba32(new Vector3(1, .1f, .133f)); Assert.Equal(255, color4.R); Assert.Equal(Math.Round(.1f * 255), color4.G); Assert.Equal(Math.Round(.133f * 255), color4.B); Assert.Equal(255, color4.A); - Rgba32 color5 = new Rgba32(new Vector4(1, .1f, .133f, .5f)); + var color5 = new Rgba32(new Vector4(1, .1f, .133f, .5f)); Assert.Equal(255, color5.R); Assert.Equal(Math.Round(.1f * 255), color5.G); Assert.Equal(Math.Round(.133f * 255), color5.B); @@ -112,7 +112,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public unsafe void ByteLayout() { - Rgba32 color = new Rgba32(1, 2, 3, 4); + var color = new Rgba32(1, 2, 3, 4); byte* colorBase = (byte*)&color; Assert.Equal(1, colorBase[0]); Assert.Equal(2, colorBase[1]); @@ -181,23 +181,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One, new Rgba32(Vector4.One * +1234.0f).ToVector4()); } - [Fact] - public void Rgba32_ToRgb24() - { - // arrange - var rgba = new Rgba32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(0x1a, 0, 0x80); - - // act - rgba.ToRgb24(ref actual); - - // assert - Assert.Equal(expected.R, actual.R); - Assert.Equal(expected.G, actual.G); - Assert.Equal(expected.B, actual.B); - } - [Fact] public void Rgba32_ToRgba32() { @@ -207,52 +190,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(0x1a, 0, 0x80, 0); // act - rgba.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba32_ToBgr24() - { - // arrange - var rgba = new Rgba32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(0x1a, 0, 0x80); - - // act - rgba.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba32_ToBgra32() - { - // arrange - var rgba = new Rgba32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(0x1a, 0, 0x80, 0); - - // act - rgba.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba32_ToArgb32() - { - // arrange - var rgba = new Rgba32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(0x1a, 0, 0x80, 0); - - // act - rgba.ToArgb32(ref actual); + actual.PackFromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -268,7 +206,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act rgba.PackFromRgba32(expected); - rgba.ToRgba32(ref actual); + actual.PackFromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -284,7 +222,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act rgba.PackFromBgra32(expected); - rgba.ToBgra32(ref actual); + actual.PackFromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -300,14 +238,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act rgba.PackFromArgb32(expected); - rgba.ToArgb32(ref actual); + actual.PackFromRgba32(rgba); // assert Assert.Equal(expected, actual); } [Fact] - public void Rgba32_PackFromRgb48_ToRgb48() + public void Rgba32_PackFromRgb48() { // arrange var input = default(Rgba32); @@ -316,14 +254,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgb48(expected); - input.ToRgb48(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); } [Fact] - public void Rgba32_PackFromRgba64_ToRgba64() + public void Rgba32_PackFromRgba64() { // arrange var input = default(Rgba32); @@ -332,7 +270,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgba64(expected); - input.ToRgba64(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index 92b36a1c62..e9ac5377d2 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -13,33 +13,31 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void Rgba64_PackedValues() { Assert.Equal((ulong)0x73334CCC2666147B, new Rgba64(5243, 9830, 19660, 29491).PackedValue); - Assert.Equal((ulong)0x73334CCC2666147B, new Rgba64(0.08f, 0.15f, 0.30f, 0.45f).PackedValue); - var rgba = new Rgba64(0x73334CCC2666147B); - Assert.Equal(5243, rgba.R); - Assert.Equal(9830, rgba.G); - Assert.Equal(19660, rgba.B); - Assert.Equal(29491, rgba.A); // Test the limits. - Assert.Equal((ulong)0x0, new Rgba64(Vector4.Zero).PackedValue); - Assert.Equal(0xFFFFFFFFFFFFFFFF, new Rgba64(Vector4.One).PackedValue); + Assert.Equal((ulong)0x0, new Rgba64(0, 0, 0, 0).PackedValue); + Assert.Equal(0xFFFFFFFFFFFFFFFF, new Rgba64( + ushort.MaxValue, + ushort.MaxValue, + ushort.MaxValue, + ushort.MaxValue).PackedValue); + // Test data ordering - Assert.Equal(0xC7AD8F5C570A1EB8, new Rgba64(((float)0x1EB8) / 0xffff, ((float)0x570A) / 0xffff, ((float)0x8F5C) / 0xffff, ((float)0xC7AD) / 0xffff).PackedValue); - Assert.Equal(0xC7AD8F5C570A1EB8, new Rgba64(0.12f, 0.34f, 0.56f, 0.78f).PackedValue); + Assert.Equal(0xC7AD8F5C570A1EB8, new Rgba64(0x1EB8, 0x570A, 0x8F5C, 0xC7AD).PackedValue); } [Fact] public void Rgba64_ToVector4() { - Assert.Equal(Vector4.Zero, new Rgba64(Vector4.Zero).ToVector4()); - Assert.Equal(Vector4.One, new Rgba64(Vector4.One).ToVector4()); + Assert.Equal(Vector4.Zero, new Rgba64(0, 0, 0, 0).ToVector4()); + Assert.Equal(Vector4.One, new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue).ToVector4()); } [Fact] public void Rgba64_ToScaledVector4() { // arrange - var short2 = new Rgba64(Vector4.One); + var short2 = new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); // act Vector4 actual = short2.ToScaledVector4(); @@ -56,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { // arrange var pixel = default(Rgba64); - var short4 = new Rgba64(Vector4.One); + var short4 = new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); const ulong expected = 0xFFFFFFFFFFFFFFFF; // act @@ -71,128 +69,24 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void Rgba64_Clamping() { - Assert.Equal(Vector4.Zero, new Rgba64(Vector4.One * -1234.0f).ToVector4()); - Assert.Equal(Vector4.One, new Rgba64(Vector4.One * 1234.0f).ToVector4()); - } - - [Fact] - public void Rgba64_ToRgb24() - { - // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); - var actual = default(Rgb24); - var expected = new Rgb24(20, 38, 76); - - // act - rgba64.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); + var zero = default(Rgba64); + var one = default(Rgba64); + zero.PackFromVector4(Vector4.One * -1234.0f); + one.PackFromVector4(Vector4.One * 1234.0f); + Assert.Equal(Vector4.Zero, zero.ToVector4()); + Assert.Equal(Vector4.One, one.ToVector4()); } [Fact] public void Rgba64_ToRgba32() { // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); + var rgba64 = new Rgba64(5140, 9766, 19532, 29555); var actual = default(Rgba32); var expected = new Rgba32(20, 38, 76, 115); // act - rgba64.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_ToArgb32() - { - // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); - var actual = default(Argb32); - var expected = new Argb32(20, 38, 76, 115); - - // act - rgba64.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_ToBgr24() - { - // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); - var actual = default(Bgr24); - var expected = new Bgr24(20, 38, 76); - - // act - rgba64.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_ToBgra32() - { - // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); - var actual = default(Bgra32); - var expected = new Bgra32(20, 38, 76, 115); - - // act - rgba64.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_PackFromRgba32_ToRgba32() - { - // arrange - var rgba64 = default(Rgba64); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 76, 115); - - // act - rgba64.PackFromRgba32(expected); - rgba64.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rgba64); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rgba64); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); + actual = rgba64.ToRgba32(); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs index a21b647a74..9b5fceac77 100644 --- a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs @@ -19,12 +19,12 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void AreEqual() { - RgbaVector color1 = new RgbaVector(0, 0, 0F); - RgbaVector color2 = new RgbaVector(0, 0, 0, 1F); - RgbaVector color3 = RgbaVector.FromHex("#000"); - RgbaVector color4 = RgbaVector.FromHex("#000F"); - RgbaVector color5 = RgbaVector.FromHex("#000000"); - RgbaVector color6 = RgbaVector.FromHex("#000000FF"); + var color1 = new RgbaVector(0, 0, 0F); + var color2 = new RgbaVector(0, 0, 0, 1F); + var color3 = RgbaVector.FromHex("#000"); + var color4 = RgbaVector.FromHex("#000F"); + var color5 = RgbaVector.FromHex("#000000"); + var color6 = RgbaVector.FromHex("#000000FF"); Assert.Equal(color1, color2); Assert.Equal(color1, color3); @@ -39,11 +39,11 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void AreNotEqual() { - RgbaVector color1 = new RgbaVector(1, 0, 0, 1); - RgbaVector color2 = new RgbaVector(0, 0, 0, 1); - RgbaVector color3 = RgbaVector.FromHex("#000"); - RgbaVector color4 = RgbaVector.FromHex("#000000"); - RgbaVector color5 = RgbaVector.FromHex("#FF000000"); + var color1 = new RgbaVector(1, 0, 0, 1); + var color2 = new RgbaVector(0, 0, 0, 1); + var color3 = RgbaVector.FromHex("#000"); + var color4 = RgbaVector.FromHex("#000000"); + var color5 = RgbaVector.FromHex("#FF000000"); Assert.NotEqual(color1, color2); Assert.NotEqual(color1, color3); @@ -57,29 +57,17 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void ConstructorAssignsProperties() { - RgbaVector color1 = new RgbaVector(1, .1F, .133F, .864F); + var color1 = new RgbaVector(1, .1F, .133F, .864F); Assert.Equal(1F, color1.R); Assert.Equal(.1F, color1.G); Assert.Equal(.133F, color1.B); Assert.Equal(.864F, color1.A); - RgbaVector color2 = new RgbaVector(1, .1f, .133f); + var color2 = new RgbaVector(1, .1f, .133f); Assert.Equal(1F, color2.R); Assert.Equal(.1F, color2.G); Assert.Equal(.133F, color2.B); Assert.Equal(1F, color2.A); - - RgbaVector color4 = new RgbaVector(new Vector3(1, .1f, .133f)); - Assert.Equal(1F, color4.R); - Assert.Equal(.1F, color4.G); - Assert.Equal(.133F, color4.B); - Assert.Equal(1F, color4.A); - - RgbaVector color5 = new RgbaVector(new Vector4(1, .1f, .133f, .5f)); - Assert.Equal(1F, color5.R); - Assert.Equal(.1F, color5.G); - Assert.Equal(.133F, color5.B); - Assert.Equal(.5F, color5.A); } /// @@ -88,7 +76,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void FromAndToHex() { - RgbaVector color = RgbaVector.FromHex("#AABBCCDD"); + var color = RgbaVector.FromHex("#AABBCCDD"); Assert.Equal(170 / 255F, color.R); Assert.Equal(187 / 255F, color.G); Assert.Equal(204 / 255F, color.B); @@ -116,7 +104,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void FloatLayout() { - RgbaVector color = new RgbaVector(1F, 2, 3, 4); + var color = new RgbaVector(1F, 2, 3, 4); Vector4 colorBase = Unsafe.As(ref Unsafe.Add(ref color, 0)); float[] ordered = new float[4]; colorBase.CopyTo(ordered); @@ -128,7 +116,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void RgbaVector_PackFromRgb48_ToRgb48() + public void RgbaVector_PackFromRgb48() { // arrange var input = default(RgbaVector); @@ -137,14 +125,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgb48(expected); - input.ToRgb48(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); } [Fact] - public void RgbaVector_PackFromRgba64_ToRgba64() + public void RgbaVector_PackFromRgba64() { // arrange var input = default(RgbaVector); @@ -153,7 +141,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgba64(expected); - input.ToRgba64(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index 5c75fcbbbc..5f2f45b3be 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // arrange var pixel = default(Short2); var short2 = new Short2(Vector2.One * 0x7FFF); - ulong expected = 0x7FFF7FFF; + const ulong expected = 0x7FFF7FFF; // act Vector4 scaled = short2.ToScaledVector4(); @@ -79,21 +79,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void Short2_ToRgb24() - { - // arrange - var short2 = new Short2(127.5f, -5.3f); - var actual = default(Rgb24); - var expected = new Rgb24(128, 127, 0); - - // act - short2.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - [Fact] public void Short2_ToRgba32() { @@ -103,52 +88,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(128, 127, 0, 255); // act - short2.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short2_ToBgr24() - { - // arrange - var short2 = new Short2(127.5f, -5.3f); - var actual = default(Bgr24); - var expected = new Bgr24(128, 127, 0); - - // act - short2.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short2_ToArgb32() - { - // arrange - var short2 = new Short2(127.5f, -5.3f); - var actual = default(Argb32); - var expected = new Argb32(128, 127, 0, 255); - - // act - short2.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short2_ToBgra32() - { - // arrange - var short2 = new Short2(127.5f, -5.3f); - var actual = default(Bgra32); - var expected = new Bgra32(128, 127, 0, 255); - - // act - short2.ToBgra32(ref actual); + actual = short2.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -164,14 +104,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short2.PackFromRgba32(expected); - short2.ToRgba32(ref actual); + actual = short2.ToRgba32(); // assert Assert.Equal(expected, actual); } [Fact] - public void Short2_PackFromRgb48_ToRgb48() + public void Short2_PackFromRgb48() { // arrange var input = default(Short2); @@ -180,14 +120,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgb48(expected); - input.ToRgb48(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); } [Fact] - public void Short2_PackFromRgba64_ToRgba64() + public void Short2_PackFromRgba64() { // arrange var input = default(Short2); @@ -196,7 +136,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgba64(expected); - input.ToRgba64(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index 59dc385d4d..4245fcf381 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // arrange var short4 = new Short4(Vector4.One * 0x7FFF); Vector4 scaled = short4.ToScaledVector4(); - long expected = 0x7FFF7FFF7FFF7FFF; + const long expected = 0x7FFF7FFF7FFF7FFF; // act var pixel = default(Short4); @@ -83,36 +83,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One * -0x8000, vector2); } - [Fact] - public void Short4_ToRgb24() - { - // arrange - var shortValue = new Short4(11547, 12653, 29623, 193); - var actual = default(Rgb24); - var expected = new Rgb24(172, 177, 243); - - // act - shortValue.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short4_ToBgr24() - { - // arrange - var shortValue = new Short4(11547, 12653, 29623, 193); - var actual = default(Bgr24); - var expected = new Bgr24(172, 177, 243); - - // act - shortValue.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - [Fact] public void Short4_ToRgba32() { @@ -122,37 +92,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(172, 177, 243, 128); // act - shortValue.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short4_ToBgra32() - { - // arrange - var shortValue = new Short4(11547, 12653, 29623, 193); - var actual = default(Bgra32); - var expected = new Bgra32(172, 177, 243, 128); - - // act - shortValue.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short4_ToArgb32() - { - // arrange - var shortValue = new Short4(11547, 12653, 29623, 193); - var actual = default(Argb32); - var expected = new Argb32(172, 177, 243, 128); - - // act - shortValue.ToArgb32(ref actual); + actual = shortValue.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -168,7 +108,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short4.PackFromRgba32(expected); - short4.ToRgba32(ref actual); + actual = short4.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -184,7 +124,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short4.PackFromBgra32(expected); - short4.ToBgra32(ref actual); + actual.PackFromRgba32(short4.ToRgba32()); // assert Assert.Equal(expected, actual); @@ -200,7 +140,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short4.PackFromArgb32(expected); - short4.ToArgb32(ref actual); + actual.PackFromRgba32(short4.ToRgba32()); // assert Assert.Equal(expected, actual); @@ -216,7 +156,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgb48(expected); - input.ToRgb48(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -232,7 +172,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgba64(expected); - input.ToRgba64(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs index 1fca398fcd..29c97ce35f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Tests.Colors public void Color_Types_From_Bytes_Produce_Equal_Scaled_Component_OutPut() { var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Tests.Colors public void Color_Types_From_Vector4_Produce_Equal_Scaled_Component_OutPut() { var color = new Rgba32(new Vector4(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F)); - var colorVector = new RgbaVector(new Vector4(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F)); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Tests.Colors public void Color_Types_From_Vector3_Produce_Equal_Scaled_Component_OutPut() { var color = new Rgba32(new Vector3(24 / 255F, 48 / 255F, 96 / 255F)); - var colorVector = new RgbaVector(new Vector3(24 / 255F, 48 / 255F, 96 / 255F)); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -73,76 +73,28 @@ namespace SixLabors.ImageSharp.Tests.Colors public void Color_Types_To_Vector4_Produce_Equal_OutPut() { var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.ToVector4(), colorVector.ToVector4()); } - [Fact] - public void Color_Types_To_RgbBytes_Produce_Equal_OutPut() - { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); - - var rgb = default(Rgb24); - var rgbVector = default(Rgb24); - - color.ToRgb24(ref rgb); - colorVector.ToRgb24(ref rgbVector); - - Assert.Equal(rgb, rgbVector); - } - [Fact] public void Color_Types_To_RgbaBytes_Produce_Equal_OutPut() { var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); - - var rgba = default(Rgba32); - var rgbaVector = default(Rgba32); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); - color.ToRgba32(ref rgba); - colorVector.ToRgba32(ref rgbaVector); + var rgba = color.ToRgba32(); + var rgbaVector = colorVector.ToRgba32(); Assert.Equal(rgba, rgbaVector); } - [Fact] - public void Color_Types_To_BgrBytes_Produce_Equal_OutPut() - { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); - - var bgr = default(Bgr24); - var bgrVector = default(Bgr24); - - color.ToBgr24(ref bgr); - colorVector.ToBgr24(ref bgrVector); - - Assert.Equal(bgr, bgrVector); - } - - [Fact] - public void Color_Types_To_BgraBytes_Produce_Equal_OutPut() - { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); - - var bgra = default(Bgra32); - var bgraVector = default(Bgra32); - - color.ToBgra32(ref bgra); - colorVector.ToBgra32(ref bgraVector); - - Assert.Equal(bgra, bgraVector); - } - [Fact] public void Color_Types_To_Hex_Produce_Equal_OutPut() { var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); // 183060C0 Assert.Equal(color.ToHex(), colorVector.ToHex()); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index edc6994e7a..17240839db 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -65,10 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms nameof(KnownResamplers.Lanczos8), }; - public AffineTransformTests(ITestOutputHelper output) - { - this.Output = output; - } + public AffineTransformTests(ITestOutputHelper output) => this.Output = output; /// /// The output of an "all white" image should be "all white" or transparent, regardless of the transformation and the resampler. @@ -240,12 +237,14 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms where TPixel : struct, IPixel { Span data = image.Frames.RootFrame.GetPixelSpan(); - var rgba = default(Rgba32); var white = new Rgb24(255, 255, 255); foreach (TPixel pixel in data) { - pixel.ToRgba32(ref rgba); - if (rgba.A == 0) continue; + var rgba = pixel.ToRgba32(); + if (rgba.A == 0) + { + continue; + } Assert.Equal(white, rgba.Rgb); } diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index fb32522c9c..464487f3ab 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -100,12 +100,11 @@ namespace SixLabors.ImageSharp.Tests { // Transparent pixels are much more likely to be found at the end of a palette int index = -1; - var trans = default(Rgba32); for (int i = quantized.Palette.Length - 1; i >= 0; i--) { - quantized.Palette[i].ToRgba32(ref trans); + var trans = quantized.Palette[i].ToRgba32(); - if (trans.Equals(default(Rgba32))) + if (trans.Equals(default)) { index = i; } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index 65b32e0880..70b630adf1 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -72,7 +72,10 @@ namespace SixLabors.ImageSharp.Tests extension = '.' + extension; } - if (fn != string.Empty) fn = '_' + fn; + if (fn != string.Empty) + { + fn = '_' + fn; + } string pixName = ""; @@ -274,17 +277,14 @@ namespace SixLabors.ImageSharp.Tests } public static void ModifyPixel(Image img, int x, int y, byte perChannelChange) - where TPixel : struct, IPixel - { - ModifyPixel(img.Frames.RootFrame, x, y, perChannelChange); - } + where TPixel : struct, IPixel => ModifyPixel(img.Frames.RootFrame, x, y, perChannelChange); public static void ModifyPixel(ImageFrame img, int x, int y, byte perChannelChange) where TPixel : struct, IPixel { TPixel pixel = img[x, y]; Rgba64 rgbaPixel = default; - pixel.ToRgba64(ref rgbaPixel); + rgbaPixel.PackFromScaledVector4(pixel.ToScaledVector4()); ushort change = (ushort)Math.Round((perChannelChange / 255F) * 65535F); if (rgbaPixel.R + perChannelChange <= 255) diff --git a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs index 0b1b89cc00..56cde41fc1 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs @@ -1,10 +1,24 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; using System.Numerics; namespace SixLabors.ImageSharp.Tests { + /// + /// Helper methods that allow the creation of random test data. + /// internal static class TestDataGenerator { + /// + /// Creates an of the given length consisting of random values between the two ranges. + /// + /// The pseudo-random number generator. + /// The length. + /// The minimum value. + /// The maximum value. + /// The . public static float[] GenerateRandomFloatArray(this Random rnd, int length, float minVal, float maxVal) { float[] values = new float[length]; @@ -17,6 +31,14 @@ namespace SixLabors.ImageSharp.Tests return values; } + /// + /// Creates an of the given length consisting of random values between the two ranges. + /// + /// The pseudo-random number generator. + /// The length. + /// The minimum value. + /// The maximum value. + /// The . public static Vector4[] GenerateRandomVectorArray(this Random rnd, int length, float minVal, float maxVal) { var values = new Vector4[length]; @@ -33,22 +55,39 @@ namespace SixLabors.ImageSharp.Tests return values; } - public static float[] GenerateRandomRoundedFloatArray(this Random rnd, int length, int minVal, int maxValExclusive) + /// + /// Creates an of the given length consisting of rounded random values between the two ranges. + /// + /// The pseudo-random number generator. + /// The length. + /// The minimum value. + /// The maximum value. + /// The . + public static float[] GenerateRandomRoundedFloatArray(this Random rnd, int length, float minVal, float maxVal) { float[] values = new float[length]; for (int i = 0; i < length; i++) { - int val = rnd.Next(minVal, maxValExclusive); - values[i] = (float)val; + values[i] = (float)Math.Round(rnd.GetRandomFloat(minVal, maxVal)); } return values; } - private static float GetRandomFloat(Random rnd, float minVal, float maxVal) + /// + /// Creates an of the given length consisting of random values. + /// + /// The pseudo-random number generator. + /// The length. + /// The . + public static byte[] GenerateRandomByteArray(this Random rnd, int length) { - return (float)rnd.NextDouble() * (maxVal - minVal) + minVal; + byte[] values = new byte[length]; + rnd.NextBytes(values); + return values; } + + private static float GetRandomFloat(this Random rnd, float minVal, float maxVal) => ((float)rnd.NextDouble() * (maxVal - minVal)) + minVal; } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs index 5a14f2e26e..e6a5ffc84b 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs @@ -80,10 +80,10 @@ namespace SixLabors.ImageSharp.Tests } else { - ca.ToRgb24(ref rgb1); - cb.ToRgb24(ref rgb2); + rgb1 = ca.ToRgba32().Rgb; + rgb2 = cb.ToRgba32().Rgb; - if (rgb1.R != rgb2.R || rgb1.G != rgb2.G || rgb1.B != rgb2.B) + if (!rgb1.Equals(rgb2)) { return false; } @@ -94,10 +94,7 @@ namespace SixLabors.ImageSharp.Tests return true; } - public static string ToCsv(this IEnumerable items, string separator = ",") - { - return String.Join(separator, items.Select(o => String.Format(CultureInfo.InvariantCulture, "{0}", o))); - } + public static string ToCsv(this IEnumerable items, string separator = ",") => string.Join(separator, items.Select(o => string.Format(CultureInfo.InvariantCulture, "{0}", o))); public static Type GetClrType(this PixelTypes pixelType) => PixelTypes2ClrTypes[pixelType]; @@ -141,10 +138,7 @@ namespace SixLabors.ImageSharp.Tests internal static PixelTypes[] GetAllPixelTypes() => (PixelTypes[])Enum.GetValues(typeof(PixelTypes)); internal static TPixel GetPixelOfNamedColor(string colorName) - where TPixel : struct, IPixel - { - return (TPixel)typeof(NamedColors).GetTypeInfo().GetField(colorName).GetValue(null); - } + where TPixel : struct, IPixel => (TPixel)typeof(NamedColors).GetTypeInfo().GetField(colorName).GetValue(null); /// /// Utility for testing image processor extension methods: diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs index 8a3e69059f..30bb16c2a0 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs @@ -3,6 +3,8 @@ using System; using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats; diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs index 5305eb2ba3..1d284af15e 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs @@ -2,36 +2,26 @@ // Licensed under the Apache License, Version 2.0. using System; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; -using Xunit.Abstractions; - using System.Collections.Concurrent; using System.IO; - using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; +using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests { - using SixLabors.Memory; - public class TestImageProviderTests { - public TestImageProviderTests(ITestOutputHelper output) - { - this.Output = output; - } + public TestImageProviderTests(ITestOutputHelper output) => this.Output = output; private ITestOutputHelper Output { get; } [Theory] [WithBlankImages(1, 1, PixelTypes.Rgba32)] public void NoOutputSubfolderIsPresentByDefault(TestImageProvider provider) - where TPixel : struct, IPixel - { - Assert.Empty(provider.Utility.OutputSubfolderName); - } + where TPixel : struct, IPixel => Assert.Empty(provider.Utility.OutputSubfolderName); [Theory] [WithBlankImages(42, 666, PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.HalfSingle, "hello")] @@ -64,10 +54,7 @@ namespace SixLabors.ImageSharp.Tests [WithBlankImages(1, 1, PixelTypes.Alpha8, PixelTypes.Alpha8)] [WithBlankImages(1, 1, PixelTypes.Argb32, PixelTypes.Argb32)] public void PixelType_PropertyValueIsCorrect(TestImageProvider provider, PixelTypes expected) - where TPixel : struct, IPixel - { - Assert.Equal(expected, provider.PixelType); - } + where TPixel : struct, IPixel => Assert.Equal(expected, provider.PixelType); [Theory] [WithFile(TestImages.Bmp.Car, PixelTypes.All, 88)] @@ -96,7 +83,7 @@ namespace SixLabors.ImageSharp.Tests // Couldn't make xUnit happy without this hackery: - private static ConcurrentDictionary invocationCounts = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary invocationCounts = new ConcurrentDictionary(); private string callerName = null; @@ -160,7 +147,7 @@ namespace SixLabors.ImageSharp.Tests return new Image(42, 42); } - private static ConcurrentDictionary invocationCounts = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary invocationCounts = new ConcurrentDictionary(); private string callerName = null; @@ -287,14 +274,12 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(10, img.Width); Assert.Equal(20, img.Height); - var rgba = default(Rgba32); - Buffer2D pixels = img.GetRootFramePixelBuffer(); for (int y = 0; y < pixels.Height; y++) { for (int x = 0; x < pixels.Width; x++) { - pixels[x, y].ToRgba32(ref rgba); + var rgba = pixels[x, y].ToRgba32(); Assert.Equal(255, rgba.R); Assert.Equal(100, rgba.G); @@ -311,10 +296,7 @@ namespace SixLabors.ImageSharp.Tests /// /// public static Image CreateTestImage() - where TPixel : struct, IPixel - { - return new Image(3, 3); - } + where TPixel : struct, IPixel => new Image(3, 3); [Theory] [WithMemberFactory(nameof(CreateTestImage), PixelTypes.All)]