diff --git a/src/ImageSharp/Common/Helpers/InliningOptions.cs b/src/ImageSharp/Common/Helpers/InliningOptions.cs index 4bc8ef3c87..1ae880787e 100644 --- a/src/ImageSharp/Common/Helpers/InliningOptions.cs +++ b/src/ImageSharp/Common/Helpers/InliningOptions.cs @@ -12,6 +12,10 @@ namespace SixLabors.ImageSharp /// internal static class InliningOptions { + /// + /// regardless of the build conditions. + /// + public const MethodImplOptions AlwaysInline = MethodImplOptions.AggressiveInlining; #if PROFILING public const MethodImplOptions HotPath = MethodImplOptions.NoInlining; public const MethodImplOptions ShortMethod = MethodImplOptions.NoInlining; diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs index 60e7fdd33d..cd96b51e92 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs @@ -537,7 +537,7 @@ private static void Shuffle4Slice3( /// The first vector to multiply. /// The second vector to multiply. /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(InliningOptions.AlwaysInline)] public static Vector256 MultiplyAdd( in Vector256 va, in Vector256 vm0, diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx2.cs index f9334de73b..216c12735f 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx2.cs @@ -22,60 +22,39 @@ public FromCmykAvx2(int precision) { } - protected override void ConvertCoreVectorized(in ComponentValues values, Span result) + protected override void ConvertCoreVectorizedInplace(in ComponentValues values) { #if SUPPORTS_RUNTIME_INTRINSICS - ref Vector256 cBase = + ref Vector256 c0Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); - ref Vector256 mBase = + ref Vector256 c1Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); - ref Vector256 yBase = + ref Vector256 c2Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); - ref Vector256 kBase = + ref Vector256 c3Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); - ref Vector256 resultBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(result)); - // Used for the color conversion var scale = Vector256.Create(1 / this.MaximumValue); - var one = Vector256.Create(1F); - - // Used for packing - ref byte control = ref MemoryMarshal.GetReference(HwIntrinsics.PermuteMaskEvenOdd8x32); - Vector256 vcontrol = Unsafe.As>(ref control); - int n = result.Length / 8; - for (int i = 0; i < n; i++) + nint n = values.Component0.Length / 8; + for (nint i = 0; i < n; i++) { - Vector256 k = Avx2.PermuteVar8x32(Unsafe.Add(ref kBase, i), vcontrol); - Vector256 c = Avx2.PermuteVar8x32(Unsafe.Add(ref cBase, i), vcontrol); - Vector256 m = Avx2.PermuteVar8x32(Unsafe.Add(ref mBase, i), vcontrol); - Vector256 y = Avx2.PermuteVar8x32(Unsafe.Add(ref yBase, i), vcontrol); + ref Vector256 c = ref Unsafe.Add(ref c0Base, i); + ref Vector256 m = ref Unsafe.Add(ref c1Base, i); + ref Vector256 y = ref Unsafe.Add(ref c2Base, i); + Vector256 k = Unsafe.Add(ref c3Base, i); k = Avx.Multiply(k, scale); - c = Avx.Multiply(Avx.Multiply(c, k), scale); m = Avx.Multiply(Avx.Multiply(m, k), scale); y = Avx.Multiply(Avx.Multiply(y, k), scale); - - Vector256 cmLo = Avx.UnpackLow(c, m); - Vector256 yoLo = Avx.UnpackLow(y, one); - Vector256 cmHi = Avx.UnpackHigh(c, m); - Vector256 yoHi = Avx.UnpackHigh(y, one); - - ref Vector256 destination = ref Unsafe.Add(ref resultBase, i * 4); - - destination = Avx.Shuffle(cmLo, yoLo, 0b01_00_01_00); - Unsafe.Add(ref destination, 1) = Avx.Shuffle(cmLo, yoLo, 0b11_10_11_10); - Unsafe.Add(ref destination, 2) = Avx.Shuffle(cmHi, yoHi, 0b01_00_01_00); - Unsafe.Add(ref destination, 3) = Avx.Shuffle(cmHi, yoHi, 0b11_10_11_10); } #endif } - protected override void ConvertCore(in ComponentValues values, Span result) => - FromCmykBasic.ConvertCore(values, result, this.MaximumValue); + protected override void ConvertCoreInplace(in ComponentValues values) => + FromCmykBasic.ConvertCoreInplace(values, this.MaximumValue); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykBasic.cs index 6cbd52ec3d..b0ad50301b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykBasic.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykBasic.cs @@ -15,38 +15,27 @@ public FromCmykBasic(int precision) { } - public override void ConvertToRgba(in ComponentValues values, Span result) - { - ConvertCore(values, result, this.MaximumValue); - } + public override void ConvertToRgbInplace(in ComponentValues values) => + ConvertCoreInplace(values, this.MaximumValue); - internal static void ConvertCore(in ComponentValues values, Span result, float maxValue) + internal static void ConvertCoreInplace(in ComponentValues values, float maxValue) { - ReadOnlySpan cVals = values.Component0; - ReadOnlySpan mVals = values.Component1; - ReadOnlySpan yVals = values.Component2; - ReadOnlySpan kVals = values.Component3; - - var v = new Vector4(0, 0, 0, 1F); - - var maximum = 1 / maxValue; - var scale = new Vector4(maximum, maximum, maximum, 1F); + Span c0 = values.Component0; + Span c1 = values.Component1; + Span c2 = values.Component2; + Span c3 = values.Component3; - for (int i = 0; i < result.Length; i++) + float scale = 1 / maxValue; + for (int i = 0; i < c0.Length; i++) { - float c = cVals[i]; - float m = mVals[i]; - float y = yVals[i]; - float k = kVals[i] / maxValue; - - v.X = c * k; - v.Y = m * k; - v.Z = y * k; - v.W = 1F; - - v *= scale; - - result[i] = v; + float c = c0[i]; + float m = c1[i]; + float y = c2[i]; + float k = c3[i] / maxValue; + + c0[i] = c * k * scale; + c1[i] = m * k * scale; + c2[i] = y * k * scale; } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs index e75634b0fa..0da4c9ec23 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs @@ -18,7 +18,7 @@ public FromCmykVector8(int precision) { } - protected override void ConvertCoreVectorized(in ComponentValues values, Span result) + protected override void ConvertCoreVectorizedInplace(in ComponentValues values) { ref Vector cBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); @@ -29,43 +29,25 @@ protected override void ConvertCoreVectorized(in ComponentValues values, Span kBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); - ref Vector4Octet resultBase = - ref Unsafe.As(ref MemoryMarshal.GetReference(result)); - - Vector4Pair cc = default; - Vector4Pair mm = default; - Vector4Pair yy = default; - ref Vector ccRefAsVector = ref Unsafe.As>(ref cc); - ref Vector mmRefAsVector = ref Unsafe.As>(ref mm); - ref Vector yyRefAsVector = ref Unsafe.As>(ref yy); - var scale = new Vector(1 / this.MaximumValue); // Walking 8 elements at one step: - int n = result.Length / 8; - for (int i = 0; i < n; i++) + nint n = values.Component0.Length / 8; + for (nint i = 0; i < n; i++) { - Vector c = Unsafe.Add(ref cBase, i); - Vector m = Unsafe.Add(ref mBase, i); - Vector y = Unsafe.Add(ref yBase, i); + ref Vector c = ref Unsafe.Add(ref cBase, i); + ref Vector m = ref Unsafe.Add(ref mBase, i); + ref Vector y = ref Unsafe.Add(ref yBase, i); Vector k = Unsafe.Add(ref kBase, i) * scale; c = (c * k) * scale; m = (m * k) * scale; y = (y * k) * scale; - - ccRefAsVector = c; - mmRefAsVector = m; - yyRefAsVector = y; - - // Collect (c0,c1...c8) (m0,m1...m8) (y0,y1...y8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order: - ref Vector4Octet destination = ref Unsafe.Add(ref resultBase, i); - destination.Pack(ref cc, ref mm, ref yy); } } - protected override void ConvertCore(in ComponentValues values, Span result) => - FromCmykBasic.ConvertCore(values, result, this.MaximumValue); + protected override void ConvertCoreInplace(in ComponentValues values) => + FromCmykBasic.ConvertCoreInplace(values, this.MaximumValue); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx2.cs index 45846a6b56..eca6b62920 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx2.cs @@ -22,42 +22,26 @@ public FromGrayscaleAvx2(int precision) { } - protected override void ConvertCoreVectorized(in ComponentValues values, Span result) + protected override void ConvertCoreVectorizedInplace(in ComponentValues values) { #if SUPPORTS_RUNTIME_INTRINSICS - ref Vector256 gBase = + ref Vector256 c0Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); - ref Vector256 resultBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(result)); - // Used for the color conversion var scale = Vector256.Create(1 / this.MaximumValue); - var one = Vector256.Create(1F); - - // Used for packing - ref byte control = ref MemoryMarshal.GetReference(HwIntrinsics.PermuteMaskEvenOdd8x32); - Vector256 vcontrol = Unsafe.As>(ref control); - int n = result.Length / 8; - for (int i = 0; i < n; i++) + nint n = values.Component0.Length / 8; + for (nint i = 0; i < n; i++) { - Vector256 g = Avx.Multiply(Unsafe.Add(ref gBase, i), scale); - - g = Avx2.PermuteVar8x32(g, vcontrol); - - ref Vector256 destination = ref Unsafe.Add(ref resultBase, i * 4); - - destination = Avx.Blend(Avx.Permute(g, 0b00_00_00_00), one, 0b1000_1000); - Unsafe.Add(ref destination, 1) = Avx.Blend(Avx.Shuffle(g, g, 0b01_01_01_01), one, 0b1000_1000); - Unsafe.Add(ref destination, 2) = Avx.Blend(Avx.Shuffle(g, g, 0b10_10_10_10), one, 0b1000_1000); - Unsafe.Add(ref destination, 3) = Avx.Blend(Avx.Shuffle(g, g, 0b11_11_11_11), one, 0b1000_1000); + ref Vector256 c0 = ref Unsafe.Add(ref c0Base, i); + c0 = Avx.Multiply(c0, scale); } #endif } - protected override void ConvertCore(in ComponentValues values, Span result) => - FromGrayscaleBasic.ConvertCore(values, result, this.MaximumValue); + protected override void ConvertCoreInplace(in ComponentValues values) => + FromGrayscaleBasic.ScaleValues(values.Component0, this.MaximumValue); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleBasic.cs index 0b7a220d94..76d57bf069 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleBasic.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleBasic.cs @@ -17,25 +17,35 @@ public FromGrayscaleBasic(int precision) { } - public override void ConvertToRgba(in ComponentValues values, Span result) - { - ConvertCore(values, result, this.MaximumValue); - } + public override void ConvertToRgbInplace(in ComponentValues values) => + ScaleValues(values.Component0, this.MaximumValue); - internal static void ConvertCore(in ComponentValues values, Span result, float maxValue) + internal static void ScaleValues(Span values, float maxValue) { - var maximum = 1 / maxValue; - var scale = new Vector4(maximum, maximum, maximum, 1F); + Span vecValues = MemoryMarshal.Cast(values); - ref float sBase = ref MemoryMarshal.GetReference(values.Component0); - ref Vector4 dBase = ref MemoryMarshal.GetReference(result); + var scaleVector = new Vector4(1 / maxValue); - for (int i = 0; i < result.Length; i++) + for (int i = 0; i < vecValues.Length; i++) { - var v = new Vector4(Unsafe.Add(ref sBase, i)); - v.W = 1f; - v *= scale; - Unsafe.Add(ref dBase, i) = v; + vecValues[i] *= scaleVector; + } + + values = values.Slice(vecValues.Length * 4); + if (!values.IsEmpty) + { + float scaleValue = 1f / maxValue; + values[0] *= scaleValue; + + if ((uint)values.Length > 1) + { + values[1] *= scaleValue; + + if ((uint)values.Length > 2) + { + values[2] *= scaleValue; + } + } } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx2.cs index 8f04c91528..557e4e4173 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx2.cs @@ -22,7 +22,7 @@ public FromRgbAvx2(int precision) { } - protected override void ConvertCoreVectorized(in ComponentValues values, Span result) + protected override void ConvertCoreVectorizedInplace(in ComponentValues values) { #if SUPPORTS_RUNTIME_INTRINSICS ref Vector256 rBase = @@ -32,41 +32,23 @@ protected override void ConvertCoreVectorized(in ComponentValues values, Span bBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); - ref Vector256 resultBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(result)); - // Used for the color conversion var scale = Vector256.Create(1 / this.MaximumValue); - var one = Vector256.Create(1F); - - // Used for packing - ref byte control = ref MemoryMarshal.GetReference(HwIntrinsics.PermuteMaskEvenOdd8x32); - Vector256 vcontrol = Unsafe.As>(ref control); - - int n = result.Length / 8; - for (int i = 0; i < n; i++) + nint n = values.Component0.Length / 8; + for (nint i = 0; i < n; i++) { - Vector256 r = Avx.Multiply(Avx2.PermuteVar8x32(Unsafe.Add(ref rBase, i), vcontrol), scale); - Vector256 g = Avx.Multiply(Avx2.PermuteVar8x32(Unsafe.Add(ref gBase, i), vcontrol), scale); - Vector256 b = Avx.Multiply(Avx2.PermuteVar8x32(Unsafe.Add(ref bBase, i), vcontrol), scale); - - Vector256 rgLo = Avx.UnpackLow(r, g); - Vector256 boLo = Avx.UnpackLow(b, one); - Vector256 rgHi = Avx.UnpackHigh(r, g); - Vector256 boHi = Avx.UnpackHigh(b, one); - - ref Vector256 destination = ref Unsafe.Add(ref resultBase, i * 4); - - destination = Avx.Shuffle(rgLo, boLo, 0b01_00_01_00); - Unsafe.Add(ref destination, 1) = Avx.Shuffle(rgLo, boLo, 0b11_10_11_10); - Unsafe.Add(ref destination, 2) = Avx.Shuffle(rgHi, boHi, 0b01_00_01_00); - Unsafe.Add(ref destination, 3) = Avx.Shuffle(rgHi, boHi, 0b11_10_11_10); + ref Vector256 r = ref Unsafe.Add(ref rBase, i); + ref Vector256 g = ref Unsafe.Add(ref gBase, i); + ref Vector256 b = ref Unsafe.Add(ref bBase, i); + r = Avx.Multiply(r, scale); + g = Avx.Multiply(g, scale); + b = Avx.Multiply(b, scale); } #endif } - protected override void ConvertCore(in ComponentValues values, Span result) => - FromRgbBasic.ConvertCore(values, result, this.MaximumValue); + protected override void ConvertCoreInplace(in ComponentValues values) => + FromRgbBasic.ConvertCoreInplace(values, this.MaximumValue); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbBasic.cs index ddca3fe2f6..1425e7b584 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbBasic.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbBasic.cs @@ -3,6 +3,7 @@ using System; using System.Numerics; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { @@ -15,36 +16,16 @@ public FromRgbBasic(int precision) { } - public override void ConvertToRgba(in ComponentValues values, Span result) + public override void ConvertToRgbInplace(in ComponentValues values) { - ConvertCore(values, result, this.MaximumValue); + ConvertCoreInplace(values, this.MaximumValue); } - internal static void ConvertCore(in ComponentValues values, Span result, float maxValue) + internal static void ConvertCoreInplace(ComponentValues values, float maxValue) { - ReadOnlySpan rVals = values.Component0; - ReadOnlySpan gVals = values.Component1; - ReadOnlySpan bVals = values.Component2; - - var v = new Vector4(0, 0, 0, 1); - - var maximum = 1 / maxValue; - var scale = new Vector4(maximum, maximum, maximum, 1F); - - for (int i = 0; i < result.Length; i++) - { - float r = rVals[i]; - float g = gVals[i]; - float b = bVals[i]; - - v.X = r; - v.Y = g; - v.Z = b; - - v *= scale; - - result[i] = v; - } + FromGrayscaleBasic.ScaleValues(values.Component0, maxValue); + FromGrayscaleBasic.ScaleValues(values.Component1, maxValue); + FromGrayscaleBasic.ScaleValues(values.Component2, maxValue); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs index 763064d1e0..a00361d970 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs @@ -18,50 +18,32 @@ public FromRgbVector8(int precision) { } - protected override void ConvertCoreVectorized(in ComponentValues values, Span result) + protected override void ConvertCoreVectorizedInplace(in ComponentValues values) { ref Vector rBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); ref Vector gBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); ref Vector bBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); - - ref Vector4Octet resultBase = - ref Unsafe.As(ref MemoryMarshal.GetReference(result)); - - Vector4Pair rr = default; - Vector4Pair gg = default; - Vector4Pair bb = default; - ref Vector rrRefAsVector = ref Unsafe.As>(ref rr); - ref Vector ggRefAsVector = ref Unsafe.As>(ref gg); - ref Vector bbRefAsVector = ref Unsafe.As>(ref bb); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); var scale = new Vector(1 / this.MaximumValue); // Walking 8 elements at one step: - int n = result.Length / 8; - for (int i = 0; i < n; i++) + nint n = values.Component0.Length / 8; + for (nint i = 0; i < n; i++) { - Vector r = Unsafe.Add(ref rBase, i); - Vector g = Unsafe.Add(ref gBase, i); - Vector b = Unsafe.Add(ref bBase, i); + ref Vector r = ref Unsafe.Add(ref rBase, i); + ref Vector g = ref Unsafe.Add(ref gBase, i); + ref Vector b = ref Unsafe.Add(ref bBase, i); r *= scale; g *= scale; b *= scale; - - rrRefAsVector = r; - ggRefAsVector = g; - bbRefAsVector = b; - - // 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.Pack(ref rr, ref gg, ref bb); } } - protected override void ConvertCore(in ComponentValues values, Span result) => - FromRgbBasic.ConvertCore(values, result, this.MaximumValue); + protected override void ConvertCoreInplace(in ComponentValues values) => + FromRgbBasic.ConvertCoreInplace(values, this.MaximumValue); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx2.cs index f3a0636200..5aae1faa27 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx2.cs @@ -23,19 +23,16 @@ public FromYCbCrAvx2(int precision) { } - protected override void ConvertCoreVectorized(in ComponentValues values, Span result) + protected override void ConvertCoreVectorizedInplace(in ComponentValues values) { - #if SUPPORTS_RUNTIME_INTRINSICS - ref Vector256 yBase = +#if SUPPORTS_RUNTIME_INTRINSICS + ref Vector256 c0Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); - ref Vector256 cbBase = + ref Vector256 c1Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); - ref Vector256 crBase = + ref Vector256 c2Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); - ref Vector256 resultBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(result)); - // Used for the color conversion var chromaOffset = Vector256.Create(-this.HalfValue); var scale = Vector256.Create(1 / this.MaximumValue); @@ -50,19 +47,19 @@ protected override void ConvertCoreVectorized(in ComponentValues values, Span vcontrol = Unsafe.As>(ref control); // Walking 8 elements at one step: - int n = result.Length / 8; - for (int i = 0; i < n; i++) + nint n = values.Component0.Length / 8; + for (nint i = 0; i < n; i++) { // y = yVals[i]; // cb = cbVals[i] - 128F; // cr = crVals[i] - 128F; - Vector256 y = Unsafe.Add(ref yBase, i); - Vector256 cb = Avx.Add(Unsafe.Add(ref cbBase, i), chromaOffset); - Vector256 cr = Avx.Add(Unsafe.Add(ref crBase, i), chromaOffset); + ref Vector256 c0 = ref Unsafe.Add(ref c0Base, i); + ref Vector256 c1 = ref Unsafe.Add(ref c1Base, i); + ref Vector256 c2 = ref Unsafe.Add(ref c2Base, i); - y = Avx2.PermuteVar8x32(y, vcontrol); - cb = Avx2.PermuteVar8x32(cb, vcontrol); - cr = Avx2.PermuteVar8x32(cr, vcontrol); + Vector256 y = c0; + Vector256 cb = Avx.Add(c1, chromaOffset); + Vector256 cr = Avx.Add(c2, chromaOffset); // r = y + (1.402F * cr); // g = y - (0.344136F * cb) - (0.714136F * cr); @@ -72,30 +69,19 @@ protected override void ConvertCoreVectorized(in ComponentValues values, Span g = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(y, cb, gCbMult), cr, gCrMult); Vector256 b = HwIntrinsics.MultiplyAdd(y, cb, bCbMult); - // TODO: We should be saving to RGBA not Vector4 r = Avx.Multiply(Avx.RoundToNearestInteger(r), scale); g = Avx.Multiply(Avx.RoundToNearestInteger(g), scale); b = Avx.Multiply(Avx.RoundToNearestInteger(b), scale); - Vector256 vte = Avx.UnpackLow(r, b); - Vector256 vto = Avx.UnpackLow(g, va); - - ref Vector256 destination = ref Unsafe.Add(ref resultBase, i * 4); - - destination = Avx.UnpackLow(vte, vto); - Unsafe.Add(ref destination, 1) = Avx.UnpackHigh(vte, vto); - - vte = Avx.UnpackHigh(r, b); - vto = Avx.UnpackHigh(g, va); - - Unsafe.Add(ref destination, 2) = Avx.UnpackLow(vte, vto); - Unsafe.Add(ref destination, 3) = Avx.UnpackHigh(vte, vto); + c0 = r; + c1 = g; + c2 = b; } #endif } - protected override void ConvertCore(in ComponentValues values, Span result) => - FromYCbCrBasic.ConvertCore(values, result, this.MaximumValue, this.HalfValue); + protected override void ConvertCoreInplace(in ComponentValues values) => + FromYCbCrBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs index 352e4acb7e..990d29aa01 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs @@ -15,35 +15,26 @@ public FromYCbCrBasic(int precision) { } - public override void ConvertToRgba(in ComponentValues values, Span result) - { - ConvertCore(values, result, this.MaximumValue, this.HalfValue); - } + public override void ConvertToRgbInplace(in ComponentValues values) + => ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); - internal static void ConvertCore(in ComponentValues values, Span result, float maxValue, float halfValue) + internal static void ConvertCoreInplace(in ComponentValues values, float maxValue, float halfValue) { - // TODO: We can optimize a lot here with Vector and SRCS.Unsafe()! - ReadOnlySpan yVals = values.Component0; - ReadOnlySpan cbVals = values.Component1; - ReadOnlySpan crVals = values.Component2; - - var v = new Vector4(0, 0, 0, 1); + Span c0 = values.Component0; + Span c1 = values.Component1; + Span c2 = values.Component2; - var scale = new Vector4(1 / maxValue, 1 / maxValue, 1 / maxValue, 1F); + var scale = 1 / maxValue; - for (int i = 0; i < result.Length; i++) + for (int i = 0; i < c0.Length; i++) { - float y = yVals[i]; - float cb = cbVals[i] - halfValue; - float cr = crVals[i] - halfValue; - - v.X = MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero); - v.Y = MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero); - v.Z = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero); - - v *= scale; + float y = c0[i]; + float cb = c1[i] - halfValue; + float cr = c2[i] - halfValue; - result[i] = v; + c0[i] = MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero) * scale; + c1[i] = MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero) * scale; + c2[i] = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero) * scale; } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector4.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector4.cs index 42f8eef5a1..1ebc3e879d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector4.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector4.cs @@ -20,58 +20,54 @@ public FromYCbCrVector4(int precision) protected override bool IsAvailable => SimdUtils.HasVector4; - protected override void ConvertCoreVectorized(in ComponentValues values, Span result) + protected override void ConvertCoreVectorizedInplace(in ComponentValues values) { - // TODO: Find a way to properly run & test this path on AVX2 PC-s! (Have I already mentioned that Vector is terrible?) - DebugGuard.IsTrue(result.Length % 8 == 0, nameof(result), "result.Length should be divisible by 8!"); + DebugGuard.IsTrue(values.Component0.Length % 8 == 0, nameof(values), "Length should be divisible by 8!"); - ref Vector4Pair yBase = + ref Vector4Pair c0Base = ref Unsafe.As(ref MemoryMarshal.GetReference(values.Component0)); - ref Vector4Pair cbBase = + ref Vector4Pair c1Base = ref Unsafe.As(ref MemoryMarshal.GetReference(values.Component1)); - ref Vector4Pair crBase = + ref Vector4Pair c2Base = ref Unsafe.As(ref MemoryMarshal.GetReference(values.Component2)); - ref Vector4Octet resultBase = - ref Unsafe.As(ref MemoryMarshal.GetReference(result)); - var chromaOffset = new Vector4(-this.HalfValue); var maxValue = this.MaximumValue; // Walking 8 elements at one step: - int n = result.Length / 8; + nint n = values.Component0.Length / 8; - for (int i = 0; i < n; i++) + for (nint i = 0; i < n; i++) { // y = yVals[i]; - Vector4Pair y = Unsafe.Add(ref yBase, i); + ref Vector4Pair c0 = ref Unsafe.Add(ref c0Base, i); // cb = cbVals[i] - halfValue); - Vector4Pair cb = Unsafe.Add(ref cbBase, i); - cb.AddInplace(chromaOffset); + ref Vector4Pair c1 = ref Unsafe.Add(ref c1Base, i); + c1.AddInplace(chromaOffset); // cr = crVals[i] - halfValue; - Vector4Pair cr = Unsafe.Add(ref crBase, i); - cr.AddInplace(chromaOffset); + ref Vector4Pair c2 = ref Unsafe.Add(ref c2Base, i); + c2.AddInplace(chromaOffset); // r = y + (1.402F * cr); - Vector4Pair r = y; - Vector4Pair tmp = cr; + Vector4Pair r = c0; + Vector4Pair tmp = c2; tmp.MultiplyInplace(1.402F); r.AddInplace(ref tmp); // g = y - (0.344136F * cb) - (0.714136F * cr); - Vector4Pair g = y; - tmp = cb; + Vector4Pair g = c0; + tmp = c1; tmp.MultiplyInplace(-0.344136F); g.AddInplace(ref tmp); - tmp = cr; + tmp = c2; tmp.MultiplyInplace(-0.714136F); g.AddInplace(ref tmp); // b = y + (1.772F * cb); - Vector4Pair b = y; - tmp = cb; + Vector4Pair b = c0; + tmp = c1; tmp.MultiplyInplace(1.772F); b.AddInplace(ref tmp); @@ -79,14 +75,14 @@ protected override void ConvertCoreVectorized(in ComponentValues values, Span result) => - FromYCbCrBasic.ConvertCore(values, result, this.MaximumValue, this.HalfValue); + protected override void ConvertCoreInplace(in ComponentValues values) + => FromYCbCrBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs index abacf7161b..a077b9ed82 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs @@ -19,41 +19,32 @@ public FromYCbCrVector8(int precision) { } - protected override void ConvertCoreVectorized(in ComponentValues values, Span result) + protected override void ConvertCoreVectorizedInplace(in ComponentValues values) { - ref Vector yBase = + ref Vector c0Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); - ref Vector cbBase = + ref Vector c1Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); - ref Vector crBase = + ref Vector c2Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); - ref Vector4Octet resultBase = - ref Unsafe.As(ref MemoryMarshal.GetReference(result)); - var chromaOffset = new Vector(-this.HalfValue); // Walking 8 elements at one step: - int n = result.Length / 8; - - Vector4Pair rr = default; - Vector4Pair gg = default; - Vector4Pair bb = default; - - ref Vector rrRefAsVector = ref Unsafe.As>(ref rr); - ref Vector ggRefAsVector = ref Unsafe.As>(ref gg); - ref Vector bbRefAsVector = ref Unsafe.As>(ref bb); - + nint n = values.Component0.Length / 8; var scale = new Vector(1 / this.MaximumValue); - for (int i = 0; i < n; i++) + for (nint i = 0; i < n; i++) { // y = yVals[i]; // cb = cbVals[i] - 128F; // cr = crVals[i] - 128F; - Vector y = Unsafe.Add(ref yBase, i); - Vector cb = Unsafe.Add(ref cbBase, i) + chromaOffset; - Vector cr = Unsafe.Add(ref crBase, i) + chromaOffset; + ref Vector c0 = ref Unsafe.Add(ref c0Base, i); + ref Vector c1 = ref Unsafe.Add(ref c1Base, i); + ref Vector c2 = ref Unsafe.Add(ref c2Base, i); + Vector y = Unsafe.Add(ref c0Base, i); + Vector cb = Unsafe.Add(ref c1Base, i) + chromaOffset; + Vector cr = Unsafe.Add(ref c2Base, i) + chromaOffset; // r = y + (1.402F * cr); // g = y - (0.344136F * cb) - (0.714136F * cr); @@ -70,18 +61,14 @@ protected override void ConvertCoreVectorized(in ComponentValues values, Span result) => - FromYCbCrBasic.ConvertCore(values, result, this.MaximumValue, this.HalfValue); + protected override void ConvertCoreInplace(in ComponentValues values) => + FromYCbCrBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx2.cs index ea0132e1e9..a3500a096a 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx2.cs @@ -22,52 +22,42 @@ public FromYccKAvx2(int precision) { } - protected override void ConvertCoreVectorized(in ComponentValues values, Span result) + protected override void ConvertCoreVectorizedInplace(in ComponentValues values) { #if SUPPORTS_RUNTIME_INTRINSICS - ref Vector256 yBase = + ref Vector256 c0Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); - ref Vector256 cbBase = + ref Vector256 c1Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); - ref Vector256 crBase = + ref Vector256 c2Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); ref Vector256 kBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); - ref Vector256 resultBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(result)); - // Used for the color conversion var chromaOffset = Vector256.Create(-this.HalfValue); - var scale = Vector256.Create(1 / this.MaximumValue); + var scale = Vector256.Create(1 / (this.MaximumValue * this.MaximumValue)); var max = Vector256.Create(this.MaximumValue); var rCrMult = Vector256.Create(1.402F); var gCbMult = Vector256.Create(-0.344136F); var gCrMult = Vector256.Create(-0.714136F); var bCbMult = Vector256.Create(1.772F); - // Used for packing. - var va = Vector256.Create(1F); - ref byte control = ref MemoryMarshal.GetReference(HwIntrinsics.PermuteMaskEvenOdd8x32); - Vector256 vcontrol = Unsafe.As>(ref control); - // Walking 8 elements at one step: - int n = result.Length / 8; - for (int i = 0; i < n; i++) + nint n = values.Component0.Length / 8; + for (nint i = 0; i < n; i++) { // y = yVals[i]; // cb = cbVals[i] - 128F; // cr = crVals[i] - 128F; // k = kVals[i] / 256F; - Vector256 y = Unsafe.Add(ref yBase, i); - Vector256 cb = Avx.Add(Unsafe.Add(ref cbBase, i), chromaOffset); - Vector256 cr = Avx.Add(Unsafe.Add(ref crBase, i), chromaOffset); - Vector256 k = Avx.Divide(Unsafe.Add(ref kBase, i), max); - - y = Avx2.PermuteVar8x32(y, vcontrol); - cb = Avx2.PermuteVar8x32(cb, vcontrol); - cr = Avx2.PermuteVar8x32(cr, vcontrol); - k = Avx2.PermuteVar8x32(k, vcontrol); + ref Vector256 c0 = ref Unsafe.Add(ref c0Base, i); + ref Vector256 c1 = ref Unsafe.Add(ref c1Base, i); + ref Vector256 c2 = ref Unsafe.Add(ref c2Base, i); + Vector256 y = c0; + Vector256 cb = Avx.Add(c1, chromaOffset); + Vector256 cr = Avx.Add(c2, chromaOffset); + Vector256 scaledK = Avx.Multiply(Unsafe.Add(ref kBase, i), scale); // r = y + (1.402F * cr); // g = y - (0.344136F * cb) - (0.714136F * cr); @@ -82,29 +72,19 @@ protected override void ConvertCoreVectorized(in ComponentValues values, Span vte = Avx.UnpackLow(r, b); - Vector256 vto = Avx.UnpackLow(g, va); - - ref Vector256 destination = ref Unsafe.Add(ref resultBase, i * 4); - - destination = Avx.UnpackLow(vte, vto); - Unsafe.Add(ref destination, 1) = Avx.UnpackHigh(vte, vto); - - vte = Avx.UnpackHigh(r, b); - vto = Avx.UnpackHigh(g, va); + r = Avx.Multiply(r, scaledK); + g = Avx.Multiply(g, scaledK); + b = Avx.Multiply(b, scaledK); - Unsafe.Add(ref destination, 2) = Avx.UnpackLow(vte, vto); - Unsafe.Add(ref destination, 3) = Avx.UnpackHigh(vte, vto); + c0 = r; + c1 = g; + c2 = b; } #endif } - protected override void ConvertCore(in ComponentValues values, Span result) => - FromYccKBasic.ConvertCore(values, result, this.MaximumValue, this.HalfValue); + protected override void ConvertCoreInplace(in ComponentValues values) => + FromYccKBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKBasic.cs index 778e5325ff..4833f48683 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKBasic.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKBasic.cs @@ -15,39 +15,30 @@ public FromYccKBasic(int precision) { } - public override void ConvertToRgba(in ComponentValues values, Span result) - { - ConvertCore(values, result, this.MaximumValue, this.HalfValue); - } + public override void ConvertToRgbInplace(in ComponentValues values) => + ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); - internal static void ConvertCore(in ComponentValues values, Span result, float maxValue, float halfValue) + internal static void ConvertCoreInplace(in ComponentValues values, float maxValue, float halfValue) { - // TODO: We can optimize a lot here with Vector and SRCS.Unsafe()! - ReadOnlySpan yVals = values.Component0; - ReadOnlySpan cbVals = values.Component1; - ReadOnlySpan crVals = values.Component2; - ReadOnlySpan kVals = values.Component3; + Span c0 = values.Component0; + Span c1 = values.Component1; + Span c2 = values.Component2; + Span c3 = values.Component3; var v = new Vector4(0, 0, 0, 1F); - var maximum = 1 / maxValue; - var scale = new Vector4(maximum, maximum, maximum, 1F); + var scale = 1 / (maxValue * maxValue); - for (int i = 0; i < result.Length; i++) + for (int i = 0; i < values.Component0.Length; i++) { - float y = yVals[i]; - float cb = cbVals[i] - halfValue; - float cr = crVals[i] - halfValue; - float k = kVals[i] / maxValue; - - v.X = (maxValue - MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero)) * k; - v.Y = (maxValue - MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero)) * k; - v.Z = (maxValue - MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero)) * k; - v.W = 1F; - - v *= scale; - - result[i] = v; + float y = c0[i]; + float cb = c1[i] - halfValue; + float cr = c2[i] - halfValue; + float scaledK = c3[i] * scale; + + c0[i] = (maxValue - MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero)) * scaledK; + c1[i] = (maxValue - MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero)) * scaledK; + c2[i] = (maxValue - MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero)) * scaledK; } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs index c360392de8..f830e5042c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs @@ -18,46 +18,39 @@ public FromYccKVector8(int precision) { } - protected override void ConvertCoreVectorized(in ComponentValues values, Span result) + protected override void ConvertCoreVectorizedInplace(in ComponentValues values) { - ref Vector yBase = + ref Vector c0Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); - ref Vector cbBase = + ref Vector c1Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); - ref Vector crBase = + ref Vector c2Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); ref Vector kBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); - ref Vector4Octet resultBase = - ref Unsafe.As(ref MemoryMarshal.GetReference(result)); - var chromaOffset = new Vector(-this.HalfValue); // Walking 8 elements at one step: - int n = result.Length / 8; - - Vector4Pair rr = default; - Vector4Pair gg = default; - Vector4Pair bb = default; - - ref Vector rrRefAsVector = ref Unsafe.As>(ref rr); - ref Vector ggRefAsVector = ref Unsafe.As>(ref gg); - ref Vector bbRefAsVector = ref Unsafe.As>(ref bb); + nint n = values.Component0.Length / 8; - var scale = new Vector(1 / this.MaximumValue); var max = new Vector(this.MaximumValue); + var scale = new Vector(1f) / (max * max); - for (int i = 0; i < n; i++) + for (nint i = 0; i < n; i++) { // y = yVals[i]; // cb = cbVals[i] - 128F; // cr = crVals[i] - 128F; // k = kVals[i] / 256F; - Vector y = Unsafe.Add(ref yBase, i); - Vector cb = Unsafe.Add(ref cbBase, i) + chromaOffset; - Vector cr = Unsafe.Add(ref crBase, i) + chromaOffset; - Vector k = Unsafe.Add(ref kBase, i) / max; + ref Vector c0 = ref Unsafe.Add(ref c0Base, i); + ref Vector c1 = ref Unsafe.Add(ref c1Base, i); + ref Vector c2 = ref Unsafe.Add(ref c2Base, i); + + Vector y = c0; + Vector cb = c1 + chromaOffset; + Vector cr = c2 + chromaOffset; + Vector scaledK = Unsafe.Add(ref kBase, i) * scale; // r = y + (1.402F * cr); // g = y - (0.344136F * cb) - (0.714136F * cr); @@ -67,25 +60,18 @@ protected override void ConvertCoreVectorized(in ComponentValues values, Span g = y - (cb * new Vector(0.344136F)) - (cr * new Vector(0.714136F)); Vector b = y + (cb * new Vector(1.772F)); - r = (max - r.FastRound()) * k; - g = (max - g.FastRound()) * k; - b = (max - b.FastRound()) * k; - r *= scale; - g *= scale; - b *= scale; - - rrRefAsVector = r; - ggRefAsVector = g; - bbRefAsVector = b; + r = (max - r.FastRound()) * scaledK; + g = (max - g.FastRound()) * scaledK; + b = (max - b.FastRound()) * scaledK; - // 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.Pack(ref rr, ref gg, ref bb); + c0 = r; + c1 = g; + c2 = b; } } - protected override void ConvertCore(in ComponentValues values, Span result) => - FromYccKBasic.ConvertCore(values, result, this.MaximumValue, this.HalfValue); + protected override void ConvertCoreInplace(in ComponentValues values) => + FromYccKBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.VectorizedJpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.VectorizedJpegColorConverter.cs index 522be82c2d..fc4fb77860 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.VectorizedJpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.VectorizedJpegColorConverter.cs @@ -18,10 +18,11 @@ protected VectorizedJpegColorConverter(JpegColorSpace colorSpace, int precision, this.vectorSize = vectorSize; } - public sealed override void ConvertToRgba(in ComponentValues values, Span result) + public override void ConvertToRgbInplace(in ComponentValues values) { - int remainder = result.Length % this.vectorSize; - int simdCount = result.Length - remainder; + int length = values.Component0.Length; + int remainder = values.Component0.Length % this.vectorSize; + int simdCount = length - remainder; if (simdCount > 0) { // This implementation is actually AVX specific. @@ -32,15 +33,15 @@ public sealed override void ConvertToRgba(in ComponentValues values, Span result); + protected virtual void ConvertCoreVectorizedInplace(in ComponentValues values) => throw new NotImplementedException(); - protected abstract void ConvertCore(in ComponentValues values, Span result); + protected virtual void ConvertCoreInplace(in ComponentValues values) => throw new NotImplementedException(); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs index 2d24f01dd8..11ea4cda8c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs @@ -76,11 +76,10 @@ public static JpegColorConverter GetConverter(JpegColorSpace colorSpace, int pre } /// - /// He implementation of the conversion. + /// Converts planar jpeg component values in to RGB color space inplace. /// - /// The input as a stack-only struct - /// The destination buffer of values - public abstract void ConvertToRgba(in ComponentValues values, Span result); + /// The input/ouptut as a stack-only struct + public abstract void ConvertToRgbInplace(in ComponentValues values); /// /// Returns the s for all supported colorspaces and precisions. @@ -181,22 +180,22 @@ public readonly ref struct ComponentValues /// /// The component 0 (eg. Y) /// - public readonly ReadOnlySpan Component0; + public readonly Span Component0; /// - /// The component 1 (eg. Cb) + /// The component 1 (eg. Cb). In case of grayscale, it points to . /// - public readonly ReadOnlySpan Component1; + public readonly Span Component1; /// - /// The component 2 (eg. Cr) + /// The component 2 (eg. Cr). In case of grayscale, it points to . /// - public readonly ReadOnlySpan Component2; + public readonly Span Component2; /// /// The component 4 /// - public readonly ReadOnlySpan Component3; + public readonly Span Component3; /// /// Initializes a new instance of the struct. @@ -208,30 +207,19 @@ public ComponentValues(IReadOnlyList> componentBuffers, int row) this.ComponentCount = componentBuffers.Count; this.Component0 = componentBuffers[0].GetRowSpan(row); - this.Component1 = Span.Empty; - this.Component2 = Span.Empty; - this.Component3 = Span.Empty; - - if (this.ComponentCount > 1) - { - this.Component1 = componentBuffers[1].GetRowSpan(row); - if (this.ComponentCount > 2) - { - this.Component2 = componentBuffers[2].GetRowSpan(row); - if (this.ComponentCount > 3) - { - this.Component3 = componentBuffers[3].GetRowSpan(row); - } - } - } + + // In case of grayscale, Component1 and Component2 point to Component0 memory area + this.Component1 = this.ComponentCount > 1 ? componentBuffers[1].GetRowSpan(row) : this.Component0; + this.Component2 = this.ComponentCount > 2 ? componentBuffers[2].GetRowSpan(row) : this.Component0; + this.Component3 = this.ComponentCount > 3 ? componentBuffers[3].GetRowSpan(row) : Span.Empty; } - private ComponentValues( + internal ComponentValues( int componentCount, - ReadOnlySpan c0, - ReadOnlySpan c1, - ReadOnlySpan c2, - ReadOnlySpan c3) + Span c0, + Span c1, + Span c2, + Span c3) { this.ComponentCount = componentCount; this.Component0 = c0; @@ -242,111 +230,13 @@ private ComponentValues( public ComponentValues Slice(int start, int length) { - ReadOnlySpan c0 = this.Component0.Slice(start, length); - ReadOnlySpan c1 = this.ComponentCount > 1 ? this.Component1.Slice(start, length) : ReadOnlySpan.Empty; - ReadOnlySpan c2 = this.ComponentCount > 2 ? this.Component2.Slice(start, length) : ReadOnlySpan.Empty; - ReadOnlySpan c3 = this.ComponentCount > 3 ? this.Component3.Slice(start, length) : ReadOnlySpan.Empty; + Span c0 = this.Component0.Slice(start, length); + Span c1 = this.Component1.Length > 0 ? this.Component1.Slice(start, length) : Span.Empty; + Span c2 = this.Component2.Length > 0 ? this.Component2.Slice(start, length) : Span.Empty; + Span c3 = this.Component3.Length > 0 ? this.Component3.Slice(start, length) : Span.Empty; return new ComponentValues(this.ComponentCount, c0, c1, c2, c3); } } - - internal struct Vector4Octet - { -#pragma warning disable SA1132 // Do not combine fields - public Vector4 V0, V1, V2, V3, V4, V5, V6, V7; - - /// - /// Pack (r0,r1...r7) (g0,g1...g7) (b0,b1...b7) vector values as (r0,g0,b0,1), (r1,g1,b1,1) ... - /// - public void Pack(ref Vector4Pair r, ref Vector4Pair g, ref Vector4Pair b) - { - this.V0.X = r.A.X; - this.V0.Y = g.A.X; - this.V0.Z = b.A.X; - this.V0.W = 1f; - - this.V1.X = r.A.Y; - this.V1.Y = g.A.Y; - this.V1.Z = b.A.Y; - this.V1.W = 1f; - - this.V2.X = r.A.Z; - this.V2.Y = g.A.Z; - this.V2.Z = b.A.Z; - this.V2.W = 1f; - - this.V3.X = r.A.W; - this.V3.Y = g.A.W; - this.V3.Z = b.A.W; - this.V3.W = 1f; - - this.V4.X = r.B.X; - this.V4.Y = g.B.X; - this.V4.Z = b.B.X; - this.V4.W = 1f; - - this.V5.X = r.B.Y; - this.V5.Y = g.B.Y; - this.V5.Z = b.B.Y; - this.V5.W = 1f; - - this.V6.X = r.B.Z; - this.V6.Y = g.B.Z; - this.V6.Z = b.B.Z; - this.V6.W = 1f; - - this.V7.X = r.B.W; - this.V7.Y = g.B.W; - this.V7.Z = b.B.W; - this.V7.W = 1f; - } - - /// - /// Pack (g0,g1...g7) vector values as (g0,g0,g0,1), (g1,g1,g1,1) ... - /// - public void Pack(ref Vector4Pair g) - { - this.V0.X = g.A.X; - this.V0.Y = g.A.X; - this.V0.Z = g.A.X; - this.V0.W = 1f; - - this.V1.X = g.A.Y; - this.V1.Y = g.A.Y; - this.V1.Z = g.A.Y; - this.V1.W = 1f; - - this.V2.X = g.A.Z; - this.V2.Y = g.A.Z; - this.V2.Z = g.A.Z; - this.V2.W = 1f; - - this.V3.X = g.A.W; - this.V3.Y = g.A.W; - this.V3.Z = g.A.W; - this.V3.W = 1f; - - this.V4.X = g.B.X; - this.V4.Y = g.B.X; - this.V4.Z = g.B.X; - this.V4.W = 1f; - - this.V5.X = g.B.Y; - this.V5.Y = g.B.Y; - this.V5.Z = g.B.Y; - this.V5.W = 1f; - - this.V6.X = g.B.Z; - this.V6.Y = g.B.Z; - this.V6.Z = g.B.Z; - this.V6.W = 1f; - - this.V7.X = g.B.W; - this.V7.Y = g.B.W; - this.V7.Z = g.B.W; - this.V7.W = 1f; - } - } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanBuffer.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanBuffer.cs index 12ea39e37b..3664cb4eb3 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanBuffer.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanBuffer.cs @@ -80,7 +80,7 @@ public void Reset() [MethodImpl(InliningOptions.ShortMethod)] public bool HasBadMarker() => this.Marker != JpegConstants.Markers.XFF && !this.HasRestartMarker(); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(InliningOptions.AlwaysInline)] public void FillBuffer() { // Attempt to load at least the minimum number of required bits into the buffer. @@ -130,7 +130,7 @@ private static bool HasRestart(byte marker) [MethodImpl(InliningOptions.ShortMethod)] public int PeekBits(int nbits) => (int)ExtractBits(this.data, this.remainingBits - nbits, nbits); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(InliningOptions.AlwaysInline)] private static ulong ExtractBits(ulong value, int offset, int size) => (value >> offset) & (ulong)((1 << size) - 1); [MethodImpl(InliningOptions.ShortMethod)] @@ -207,7 +207,7 @@ public bool FindNextMarker() } } - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(InliningOptions.AlwaysInline)] private int ReadStream() { int value = this.badData ? 0 : this.stream.ReadByte(); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs index 313a132b81..ec7f3e5c30 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs @@ -22,7 +22,10 @@ internal class SpectralConverter : SpectralConverter, IDisposable private JpegColorConverter colorConverter; - private IMemoryOwner rgbaBuffer; + // private IMemoryOwner rgbaBuffer; + private IMemoryOwner rgbBuffer; + + private IMemoryOwner paddedProxyPixelRow; private Buffer2D pixelBuffer; @@ -40,23 +43,20 @@ public SpectralConverter(Configuration configuration, CancellationToken cancella private bool Converted => this.pixelRowCounter >= this.pixelBuffer.Height; - public Buffer2D PixelBuffer + public Buffer2D GetPixelBuffer() { - get + if (!this.Converted) { - if (!this.Converted) - { - int steps = (int)Math.Ceiling(this.pixelBuffer.Height / (float)this.pixelRowsPerStep); + int steps = (int)Math.Ceiling(this.pixelBuffer.Height / (float)this.pixelRowsPerStep); - for (int step = 0; step < steps; step++) - { - this.cancellationToken.ThrowIfCancellationRequested(); - this.ConvertNextStride(step); - } + for (int step = 0; step < steps; step++) + { + this.cancellationToken.ThrowIfCancellationRequested(); + this.ConvertNextStride(step); } - - return this.pixelBuffer; } + + return this.pixelBuffer; } /// @@ -72,7 +72,8 @@ public override void InjectFrameData(JpegFrame frame, IRawJpegData jpegData) this.pixelRowsPerStep = this.blockRowsPerStep * blockPixelHeight; // pixel buffer for resulting image - this.pixelBuffer = allocator.Allocate2D(frame.PixelWidth, frame.PixelHeight, AllocationOptions.Clean); + this.pixelBuffer = allocator.Allocate2D(frame.PixelWidth, frame.PixelHeight); + this.paddedProxyPixelRow = allocator.Allocate(frame.PixelWidth + 3); // component processors from spectral to Rgba32 var postProcessorBufferSize = new Size(c0.SizeInBlocks.Width * 8, this.pixelRowsPerStep); @@ -83,7 +84,8 @@ public override void InjectFrameData(JpegFrame frame, IRawJpegData jpegData) } // single 'stride' rgba32 buffer for conversion between spectral and TPixel - this.rgbaBuffer = allocator.Allocate(frame.PixelWidth); + // this.rgbaBuffer = allocator.Allocate(frame.PixelWidth); + this.rgbBuffer = allocator.Allocate(frame.PixelWidth * 3); // color converter from Rgba32 to TPixel this.colorConverter = this.GetColorConverter(frame, jpegData); @@ -115,7 +117,8 @@ public void Dispose() } } - this.rgbaBuffer?.Dispose(); + this.rgbBuffer?.Dispose(); + this.paddedProxyPixelRow?.Dispose(); } private void ConvertNextStride(int spectralStep) @@ -129,17 +132,38 @@ private void ConvertNextStride(int spectralStep) buffers[i] = this.componentProcessors[i].ColorBuffer; } + int width = this.pixelBuffer.Width; + for (int yy = this.pixelRowCounter; yy < maxY; yy++) { int y = yy - this.pixelRowCounter; var values = new JpegColorConverter.ComponentValues(buffers, y); - this.colorConverter.ConvertToRgba(values, this.rgbaBuffer.GetSpan()); - Span destRow = this.pixelBuffer.GetRowSpan(yy); + this.colorConverter.ConvertToRgbInplace(values); + values = values.Slice(0, width); // slice away Jpeg padding - // TODO: Investigate if slicing is actually necessary - PixelOperations.Instance.FromVector4Destructive(this.configuration, this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow); + Span r = this.rgbBuffer.Slice(0, width); + Span g = this.rgbBuffer.Slice(width, width); + Span b = this.rgbBuffer.Slice(width * 2, width); + + SimdUtils.NormalizedFloatToByteSaturate(values.Component0, r); + SimdUtils.NormalizedFloatToByteSaturate(values.Component1, g); + SimdUtils.NormalizedFloatToByteSaturate(values.Component2, b); + + // PackFromRgbPlanes expects the destination to be padded, so try to get padded span containing extra elements from the next row. + // If we can't get such a padded row because we are on a MemoryGroup boundary or at the last row, + // pack pixels to a temporary, padded proxy buffer, then copy the relevant values to the destination row. + if (this.pixelBuffer.TryGetPaddedRowSpan(yy, 3, out Span destRow)) + { + PixelOperations.Instance.PackFromRgbPlanes(this.configuration, r, g, b, destRow); + } + else + { + Span proxyRow = this.paddedProxyPixelRow.GetSpan(); + PixelOperations.Instance.PackFromRgbPlanes(this.configuration, r, g, b, proxyRow); + proxyRow.Slice(0, width).CopyTo(this.pixelBuffer.GetRowSpan(yy)); + } } this.pixelRowCounter += this.pixelRowsPerStep; diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs index b0bdbf0ed2..be03a7e7bb 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs @@ -28,7 +28,7 @@ public Image Decode(Configuration configuration, Stream stream) /// public Image Decode(Configuration configuration, Stream stream) - => this.Decode(configuration, stream); + => this.Decode(configuration, stream); /// public Task> DecodeAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index a0f69bb7bf..9a9e5eb799 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -185,7 +185,7 @@ public Image Decode(BufferedReadStream stream, CancellationToken this.InitIptcProfile(); this.InitDerivedMetadataProperties(); - return new Image(this.Configuration, spectralConverter.PixelBuffer, this.Metadata); + return new Image(this.Configuration, spectralConverter.GetPixelBuffer(), this.Metadata); } /// diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs index e764c014d3..9a0607584e 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs @@ -65,7 +65,7 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int scanDecoder.ResetInterval = 0; jpegDecoder.ParseStream(stream, scanDecoder, CancellationToken.None); - CopyImageBytesToBuffer(buffer, spectralConverter.PixelBuffer); + CopyImageBytesToBuffer(buffer, spectralConverter.GetPixelBuffer()); } else { diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index 21c19f5d52..b62c9beb54 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -116,6 +116,36 @@ public Span GetRowSpan(int y) : this.GetRowMemorySlow(y).Span; } + internal bool TryGetPaddedRowSpan(int y, int padding, out Span paddedSpan) + { + DebugGuard.MustBeGreaterThanOrEqualTo(y, 0, nameof(y)); + DebugGuard.MustBeLessThan(y, this.Height, nameof(y)); + + int stride = this.Width + padding; + if (this.cachedMemory.Length > 0) + { + paddedSpan = this.cachedMemory.Span.Slice(y * this.Width); + if (paddedSpan.Length < stride) + { + return false; + } + + paddedSpan = paddedSpan.Slice(0, stride); + return true; + } + + Memory memory = this.FastMemoryGroup.GetRemainingSliceOfBuffer(y * (long)this.Width); + + if (memory.Length < stride) + { + paddedSpan = default; + return false; + } + + paddedSpan = memory.Span.Slice(0, stride); + return true; + } + [MethodImpl(InliningOptions.ShortMethod)] internal ref T GetElementUnsafe(int x, int y) { diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs index da42b30ad8..8e6f38d145 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs @@ -39,12 +39,8 @@ internal static Memory GetBoundedSlice(this IMemoryGroup group, long st int bufferIdx = (int)(start / group.BufferLength); - if (bufferIdx < 0) - { - throw new ArgumentOutOfRangeException(nameof(start)); - } - - if (bufferIdx >= group.Count) + // if (bufferIdx < 0 || bufferIdx >= group.Count) + if ((uint)bufferIdx >= group.Count) { throw new ArgumentOutOfRangeException(nameof(start)); } @@ -61,6 +57,31 @@ internal static Memory GetBoundedSlice(this IMemoryGroup group, long st return memory.Slice(bufferStart, length); } + /// + /// Returns the slice of the buffer starting at global index that goes until the end of the buffer. + /// + internal static Memory GetRemainingSliceOfBuffer(this IMemoryGroup group, long start) + where T : struct + { + Guard.NotNull(group, nameof(group)); + Guard.IsTrue(group.IsValid, nameof(group), "Group must be valid!"); + Guard.MustBeLessThan(start, group.TotalLength, nameof(start)); + + int bufferIdx = (int)(start / group.BufferLength); + + // if (bufferIdx < 0 || bufferIdx >= group.Count) + if ((uint)bufferIdx >= group.Count) + { + throw new ArgumentOutOfRangeException(nameof(start)); + } + + int bufferStart = (int)(start % group.BufferLength); + + Memory memory = group[bufferIdx]; + + return memory.Slice(bufferStart); + } + internal static void CopyTo(this IMemoryGroup source, Span target) where T : struct { diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs index f345f58bcd..0f1ea6b815 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs @@ -32,9 +32,7 @@ internal override void PackFromRgbPlanes( { Guard.NotNull(configuration, nameof(configuration)); int count = redChannel.Length; - Guard.IsTrue(greenChannel.Length == count, nameof(greenChannel), "Channels must be of same size!"); - Guard.IsTrue(blueChannel.Length == count, nameof(blueChannel), "Channels must be of same size!"); - Guard.IsTrue(destination.Length > count + 2, nameof(destination), "'destination' must contain a padding of 3 elements!"); + GuardPackFromRgbPlanes(greenChannel, blueChannel, destination, count); SimdUtils.PackFromRgbPlanes(configuration, redChannel, greenChannel, blueChannel, destination); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs index 9633059774..d937da98fd 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs @@ -67,9 +67,7 @@ internal override void PackFromRgbPlanes( { Guard.NotNull(configuration, nameof(configuration)); int count = redChannel.Length; - Guard.IsTrue(greenChannel.Length == count, nameof(greenChannel), "Channels must be of same size!"); - Guard.IsTrue(blueChannel.Length == count, nameof(blueChannel), "Channels must be of same size!"); - Guard.IsTrue(destination.Length > count, nameof(destination), "'destination' span should not be shorter than the source channels!"); + GuardPackFromRgbPlanes(greenChannel, blueChannel, destination, count); SimdUtils.PackFromRgbPlanes(configuration, redChannel, greenChannel, blueChannel, destination); } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index c5450538e4..f748a4b574 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -181,11 +181,7 @@ internal virtual void PackFromRgbPlanes( Guard.NotNull(configuration, nameof(configuration)); int count = redChannel.Length; - Guard.IsTrue(greenChannel.Length == count, nameof(greenChannel), "Channels must be of same size!"); - Guard.IsTrue(blueChannel.Length == count, nameof(blueChannel), "Channels must be of same size!"); - Guard.IsTrue(destination.Length > count + 2, nameof(destination), "'destination' must contain a padding of 3 elements!"); - - Guard.DestinationShouldNotBeTooShort(redChannel, destination, nameof(destination)); + GuardPackFromRgbPlanes(greenChannel, blueChannel, destination, count); Rgb24 rgb24 = default; ref byte r = ref MemoryMarshal.GetReference(redChannel); @@ -201,5 +197,13 @@ internal virtual void PackFromRgbPlanes( Unsafe.Add(ref d, i).FromRgb24(rgb24); } } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void GuardPackFromRgbPlanes(ReadOnlySpan greenChannel, ReadOnlySpan blueChannel, Span destination, int count) + { + Guard.IsTrue(greenChannel.Length == count, nameof(greenChannel), "Channels must be of same size!"); + Guard.IsTrue(blueChannel.Length == count, nameof(blueChannel), "Channels must be of same size!"); + Guard.IsTrue(destination.Length > count + 2, nameof(destination), "'destination' must contain a padding of 3 elements!"); + } } } diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs index 7af2662765..8335d2fd9a 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs @@ -14,7 +14,7 @@ internal static partial class Vector4Converters /// /// Apply modifiers used requested by ToVector4() conversion. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] internal static void ApplyForwardConversionModifiers(Span vectors, PixelConversionModifiers modifiers) { if (modifiers.IsDefined(PixelConversionModifiers.SRgbCompand)) @@ -31,7 +31,7 @@ internal static void ApplyForwardConversionModifiers(Span vectors, Pixe /// /// Apply modifiers used requested by FromVector4() conversion. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] internal static void ApplyBackwardConversionModifiers(Span vectors, PixelConversionModifiers modifiers) { if (modifiers.IsDefined(PixelConversionModifiers.Premultiply)) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs index ec238608e9..1b93d01a18 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -187,6 +188,11 @@ private static void ApplyResizeFrameTransform( bool compand, bool premultiplyAlpha) { + PixelAlphaRepresentation? alphaRepresentation = PixelOperations.Instance.GetPixelTypeInfo()?.AlphaRepresentation; + + // Premultiply only if alpha representation is unknown or Unassociated: + bool needsPremultiplication = alphaRepresentation == null || alphaRepresentation.Value == PixelAlphaRepresentation.Unassociated; + premultiplyAlpha &= needsPremultiplication; PixelConversionModifiers conversionModifiers = GetModifiers(compand, premultiplyAlpha); Buffer2DRegion sourceRegion = source.PixelBuffer.GetRegion(sourceRectangle); diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/CmykColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/CmykColorConversion.cs index d17882adf6..490beec6fb 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/CmykColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/CmykColorConversion.cs @@ -19,7 +19,7 @@ public void Scalar() { var values = new JpegColorConverter.ComponentValues(this.Input, 0); - new JpegColorConverter.FromCmykBasic(8).ConvertToRgba(values, this.Output); + new JpegColorConverter.FromCmykBasic(8).ConvertToRgbInplace(values); } [Benchmark] @@ -27,7 +27,7 @@ public void SimdVector8() { var values = new JpegColorConverter.ComponentValues(this.Input, 0); - new JpegColorConverter.FromCmykVector8(8).ConvertToRgba(values, this.Output); + new JpegColorConverter.FromCmykVector8(8).ConvertToRgbInplace(values); } [Benchmark] @@ -35,7 +35,7 @@ public void SimdVectorAvx2() { var values = new JpegColorConverter.ComponentValues(this.Input, 0); - new JpegColorConverter.FromCmykAvx2(8).ConvertToRgba(values, this.Output); + new JpegColorConverter.FromCmykAvx2(8).ConvertToRgbInplace(values); } } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversionBenchmark.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversionBenchmark.cs index e93ad474b7..caed0e4e58 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversionBenchmark.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversionBenchmark.cs @@ -19,13 +19,10 @@ protected ColorConversionBenchmark(int componentCount) protected Buffer2D[] Input { get; private set; } - protected Vector4[] Output { get; private set; } - [GlobalSetup] public void Setup() { this.Input = CreateRandomValues(this.componentCount, Count); - this.Output = new Vector4[Count]; } [GlobalCleanup] diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs index b0ac1c0fc0..da2c81f869 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs @@ -44,8 +44,8 @@ public void ReadImages() } } - [Benchmark(Baseline = true, Description = "Decode Jpeg - System.Drawing")] - public SDSize JpegSystemDrawing() + [Benchmark(Baseline = true)] + public SDSize SystemDrawing() { using (var memoryStream = new MemoryStream(this.jpegBytes)) { @@ -56,12 +56,12 @@ public SDSize JpegSystemDrawing() } } - [Benchmark(Description = "Decode Jpeg - ImageSharp")] - public Size JpegImageSharp() + [Benchmark] + public Size ImageSharp() { using (var memoryStream = new MemoryStream(this.jpegBytes)) { - using (var image = Image.Load(memoryStream, new JpegDecoder { IgnoreMetadata = true })) + using (var image = Image.Load(memoryStream, new JpegDecoder { IgnoreMetadata = true })) { return new Size(image.Width, image.Height); } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/GrayscaleColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/GrayscaleColorConversion.cs index 1eba1571da..7b62e14340 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/GrayscaleColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/GrayscaleColorConversion.cs @@ -19,7 +19,7 @@ public void Scalar() { var values = new JpegColorConverter.ComponentValues(this.Input, 0); - new JpegColorConverter.FromGrayscaleBasic(8).ConvertToRgba(values, this.Output); + new JpegColorConverter.FromGrayscaleBasic(8).ConvertToRgbInplace(values); } [Benchmark] @@ -27,7 +27,7 @@ public void SimdVectorAvx2() { var values = new JpegColorConverter.ComponentValues(this.Input, 0); - new JpegColorConverter.FromGrayscaleAvx2(8).ConvertToRgba(values, this.Output); + new JpegColorConverter.FromGrayscaleAvx2(8).ConvertToRgbInplace(values); } } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/RgbColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/RgbColorConversion.cs index c1598be043..af03b31e54 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/RgbColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/RgbColorConversion.cs @@ -19,7 +19,7 @@ public void Scalar() { var values = new JpegColorConverter.ComponentValues(this.Input, 0); - new JpegColorConverter.FromRgbBasic(8).ConvertToRgba(values, this.Output); + new JpegColorConverter.FromRgbBasic(8).ConvertToRgbInplace(values); } [Benchmark] @@ -27,7 +27,7 @@ public void SimdVector8() { var values = new JpegColorConverter.ComponentValues(this.Input, 0); - new JpegColorConverter.FromRgbVector8(8).ConvertToRgba(values, this.Output); + new JpegColorConverter.FromRgbVector8(8).ConvertToRgbInplace(values); } [Benchmark] @@ -35,7 +35,7 @@ public void SimdVectorAvx2() { var values = new JpegColorConverter.ComponentValues(this.Input, 0); - new JpegColorConverter.FromRgbAvx2(8).ConvertToRgba(values, this.Output); + new JpegColorConverter.FromRgbAvx2(8).ConvertToRgbInplace(values); } } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs index 6c5732c99e..18daa364cf 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs @@ -19,7 +19,7 @@ public void Scalar() { var values = new JpegColorConverter.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYCbCrBasic(8).ConvertToRgba(values, this.Output); + new JpegColorConverter.FromYCbCrBasic(8).ConvertToRgbInplace(values); } [Benchmark(Baseline = true)] @@ -27,7 +27,7 @@ public void SimdVector() { var values = new JpegColorConverter.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYCbCrVector4(8).ConvertToRgba(values, this.Output); + new JpegColorConverter.FromYCbCrVector4(8).ConvertToRgbInplace(values); } [Benchmark] @@ -35,7 +35,7 @@ public void SimdVector8() { var values = new JpegColorConverter.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYCbCrVector8(8).ConvertToRgba(values, this.Output); + new JpegColorConverter.FromYCbCrVector8(8).ConvertToRgbInplace(values); } [Benchmark] @@ -43,7 +43,7 @@ public void SimdVectorAvx2() { var values = new JpegColorConverter.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYCbCrAvx2(8).ConvertToRgba(values, this.Output); + new JpegColorConverter.FromYCbCrAvx2(8).ConvertToRgbInplace(values); } } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YccKColorConverter.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YccKColorConverter.cs index 0a9bdb8fdd..08e5e50d19 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YccKColorConverter.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YccKColorConverter.cs @@ -19,7 +19,7 @@ public void Scalar() { var values = new JpegColorConverter.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYccKBasic(8).ConvertToRgba(values, this.Output); + new JpegColorConverter.FromYccKBasic(8).ConvertToRgbInplace(values); } [Benchmark] @@ -27,7 +27,7 @@ public void SimdVector8() { var values = new JpegColorConverter.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYccKVector8(8).ConvertToRgba(values, this.Output); + new JpegColorConverter.FromYccKVector8(8).ConvertToRgbInplace(values); } [Benchmark] @@ -35,7 +35,7 @@ public void SimdVectorAvx2() { var values = new JpegColorConverter.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYccKAvx2(8).ConvertToRgba(values, this.Output); + new JpegColorConverter.FromYccKAvx2(8).ConvertToRgbInplace(values); } } } diff --git a/tests/ImageSharp.Benchmarks/Config.cs b/tests/ImageSharp.Benchmarks/Config.cs index 63064eec5b..ccc4a7b9f6 100644 --- a/tests/ImageSharp.Benchmarks/Config.cs +++ b/tests/ImageSharp.Benchmarks/Config.cs @@ -33,7 +33,6 @@ public class MultiFramework : Config { public MultiFramework() => this.AddJob( Job.Default.WithRuntime(ClrRuntime.Net472), - Job.Default.WithRuntime(CoreRuntime.Core21), Job.Default.WithRuntime(CoreRuntime.Core31)); } @@ -41,7 +40,6 @@ public class ShortMultiFramework : Config { public ShortMultiFramework() => this.AddJob( Job.Default.WithRuntime(ClrRuntime.Net472).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3), - Job.Default.WithRuntime(CoreRuntime.Core21).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3), Job.Default.WithRuntime(CoreRuntime.Core31).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3)); } diff --git a/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs b/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs index c15f641b4a..f36ae8b4cf 100644 --- a/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs +++ b/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs @@ -31,7 +31,6 @@ public enum JpegKind public class LoadResizeSaveStressRunner { - private const int ThumbnailSize = 150; private const int Quality = 75; private const string ImageSharp = nameof(ImageSharp); private const string SystemDrawing = nameof(SystemDrawing); @@ -58,6 +57,8 @@ public class LoadResizeSaveStressRunner public JpegKind Filter { get; set; } + public int ThumbnailSize { get; set; } = 150; + private static readonly string[] ProgressiveFiles = { "ancyloscelis-apiformis-m-paraguay-face_2014-08-08-095255-zs-pmax_15046500892_o.jpg", diff --git a/tests/ImageSharp.Benchmarks/Processing/Resize.cs b/tests/ImageSharp.Benchmarks/Processing/Resize.cs index 571c92cc87..81fdbfb314 100644 --- a/tests/ImageSharp.Benchmarks/Processing/Resize.cs +++ b/tests/ImageSharp.Benchmarks/Processing/Resize.cs @@ -215,4 +215,35 @@ protected override void ExecuteResizeOperation(IImageProcessingContext ctx) // SystemDrawing | Core | Core | 3032 | 400 | 118.3 ms | 6.899 ms | 0.3781 ms | 1.00 | 0.00 | - | - | - | 96 B | // 'ImageSharp, MaxDegreeOfParallelism = 1' | Core | Core | 3032 | 400 | 122.4 ms | 15.069 ms | 0.8260 ms | 1.03 | 0.01 | - | - | - | 15712 B | } + + public class Resize_Bicubic_Compare_Rgba32_Rgb24 + { + private Resize_Bicubic_Rgb24 rgb24; + private Resize_Bicubic_Rgba32 rgba32; + + [GlobalSetup] + public void Setup() + { + this.rgb24 = new Resize_Bicubic_Rgb24(); + this.rgb24.Setup(); + this.rgba32 = new Resize_Bicubic_Rgba32(); + this.rgba32.Setup(); + } + + [GlobalCleanup] + public void Cleanup() + { + this.rgb24.Cleanup(); + this.rgba32.Cleanup(); + } + + [Benchmark] + public void SystemDrawing() => this.rgba32.SystemDrawing(); + + [Benchmark(Baseline = true)] + public void Rgba32() => this.rgba32.ImageSharp_P1(); + + [Benchmark] + public void Rgb24() => this.rgb24.ImageSharp_P1(); + } } diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs b/tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs index 2aadf02eb9..ad46731c7f 100644 --- a/tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs +++ b/tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs @@ -18,7 +18,7 @@ private LoadResizeSaveParallelMemoryStress() this.benchmarks = new LoadResizeSaveStressRunner() { // MaxDegreeOfParallelism = 10, - // Filter = JpegKind.Baseline + Filter = JpegKind.Baseline, }; this.benchmarks.Init(); } @@ -58,6 +58,7 @@ 6. ImageMagick lrs.SystemDrawingBenchmarkParallel(); break; case ConsoleKey.D2: + Console.WriteLine($"Images: {lrs.benchmarks.Images.Length}"); lrs.ImageSharpBenchmarkParallel(); break; case ConsoleKey.D3: diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 5f05621466..560a2e462b 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -356,13 +356,13 @@ public void BenchmarkYCbCr(bool simd) JpegColorConverter converter = simd ? (JpegColorConverter)new JpegColorConverter.FromYCbCrVector4(8) : new JpegColorConverter.FromYCbCrBasic(8); // Warm up: - converter.ConvertToRgba(values, result); + converter.ConvertToRgbInplace(values); using (new MeasureGuard(this.Output, $"{converter.GetType().Name} x {times}")) { for (int i = 0; i < times; i++) { - converter.ConvertToRgba(values, result); + converter.ConvertToRgbInplace(values); } } } @@ -375,6 +375,7 @@ private static JpegColorConverter.ComponentValues CreateRandomValues( float maxVal = 255f) { var rnd = new Random(seed); + var buffers = new Buffer2D[componentCount]; for (int i = 0; i < componentCount; i++) { @@ -416,39 +417,48 @@ private static void ValidateConversion( int resultBufferLength, int seed) { - JpegColorConverter.ComponentValues values = CreateRandomValues(componentCount, inputBufferLength, seed); - var result = new Vector4[resultBufferLength]; + JpegColorConverter.ComponentValues original = CreateRandomValues(componentCount, inputBufferLength, seed); + JpegColorConverter.ComponentValues values = Copy(original); - converter.ConvertToRgba(values, result); + converter.ConvertToRgbInplace(values); for (int i = 0; i < resultBufferLength; i++) { - Validate(converter.ColorSpace, values, result, i); + Validate(converter.ColorSpace, original, values, i); + } + + static JpegColorConverter.ComponentValues Copy(JpegColorConverter.ComponentValues values) + { + Span c0 = values.Component0.ToArray(); + Span c1 = values.ComponentCount > 1 ? values.Component1.ToArray().AsSpan() : c0; + Span c2 = values.ComponentCount > 2 ? values.Component2.ToArray().AsSpan() : c0; + Span c3 = values.ComponentCount > 3 ? values.Component3.ToArray().AsSpan() : Span.Empty; + return new JpegColorConverter.ComponentValues(values.ComponentCount, c0, c1, c2, c3); } } private static void Validate( JpegColorSpace colorSpace, - in JpegColorConverter.ComponentValues values, - Vector4[] result, + in JpegColorConverter.ComponentValues original, + in JpegColorConverter.ComponentValues result, int i) { switch (colorSpace) { case JpegColorSpace.Grayscale: - ValidateGrayScale(values, result, i); + ValidateGrayScale(original, result, i); break; case JpegColorSpace.Ycck: - ValidateCyyK(values, result, i); + ValidateCyyK(original, result, i); break; case JpegColorSpace.Cmyk: - ValidateCmyk(values, result, i); + ValidateCmyk(original, result, i); break; case JpegColorSpace.RGB: - ValidateRgb(values, result, i); + ValidateRgb(original, result, i); break; case JpegColorSpace.YCbCr: - ValidateYCbCr(values, result, i); + ValidateYCbCr(original, result, i); break; default: Assert.True(false, $"Colorspace {colorSpace} not supported!"); @@ -456,22 +466,20 @@ private static void Validate( } } - private static void ValidateYCbCr(in JpegColorConverter.ComponentValues values, Vector4[] result, int i) + private static void ValidateYCbCr(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i) { float y = values.Component0[i]; float cb = values.Component1[i]; float cr = values.Component2[i]; var ycbcr = new YCbCr(y, cb, cr); - Vector4 rgba = result[i]; - var actual = new Rgb(rgba.X, rgba.Y, rgba.Z); + var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); var expected = ColorSpaceConverter.ToRgb(ycbcr); Assert.Equal(expected, actual, ColorSpaceComparer); - Assert.Equal(1, rgba.W); } - private static void ValidateCyyK(in JpegColorConverter.ComponentValues values, Vector4[] result, int i) + private static void ValidateCyyK(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i) { var v = new Vector4(0, 0, 0, 1F); var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F); @@ -490,39 +498,34 @@ private static void ValidateCyyK(in JpegColorConverter.ComponentValues values, V v *= scale; - Vector4 rgba = result[i]; - var actual = new Rgb(rgba.X, rgba.Y, rgba.Z); + var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); var expected = new Rgb(v.X, v.Y, v.Z); Assert.Equal(expected, actual, ColorSpaceComparer); - Assert.Equal(1, rgba.W); } - private static void ValidateRgb(in JpegColorConverter.ComponentValues values, Vector4[] result, int i) + private static void ValidateRgb(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i) { float r = values.Component0[i]; float g = values.Component1[i]; float b = values.Component2[i]; - Vector4 rgba = result[i]; - var actual = new Rgb(rgba.X, rgba.Y, rgba.Z); + + var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); var expected = new Rgb(r / 255F, g / 255F, b / 255F); Assert.Equal(expected, actual, ColorSpaceComparer); - Assert.Equal(1, rgba.W); } - private static void ValidateGrayScale(in JpegColorConverter.ComponentValues values, Vector4[] result, int i) + private static void ValidateGrayScale(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i) { float y = values.Component0[i]; - Vector4 rgba = result[i]; - var actual = new Rgb(rgba.X, rgba.Y, rgba.Z); + var actual = new Rgb(result.Component0[i], result.Component0[i], result.Component0[i]); var expected = new Rgb(y / 255F, y / 255F, y / 255F); Assert.Equal(expected, actual, ColorSpaceComparer); - Assert.Equal(1, rgba.W); } - private static void ValidateCmyk(in JpegColorConverter.ComponentValues values, Vector4[] result, int i) + private static void ValidateCmyk(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i) { var v = new Vector4(0, 0, 0, 1F); var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F); @@ -539,12 +542,10 @@ private static void ValidateCmyk(in JpegColorConverter.ComponentValues values, V v *= scale; - Vector4 rgba = result[i]; - var actual = new Rgb(rgba.X, rgba.Y, rgba.Z); + var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); var expected = new Rgb(v.X, v.Y, v.Z); Assert.Equal(expected, actual, ColorSpaceComparer); - Assert.Equal(1, rgba.W); } } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs index 7002bfd65e..021e3d2726 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs @@ -13,9 +13,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public partial class JpegDecoderTests { [Theory] - [WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32, false)] - [WithFile(TestImages.Jpeg.Baseline.Calliphora, PixelTypes.Rgba32, true)] - [WithFile(TestImages.Jpeg.Baseline.Turtle420, PixelTypes.Rgba32, true)] + [WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgb24, false)] + [WithFile(TestImages.Jpeg.Baseline.Calliphora, PixelTypes.Rgb24, true)] + [WithFile(TestImages.Jpeg.Baseline.Turtle420, PixelTypes.Rgb24, true)] public void DecodeBaselineJpeg(TestImageProvider provider, bool enforceDiscontiguousBuffers) where TPixel : unmanaged, IPixel { @@ -26,7 +26,7 @@ static void RunTest(string providerDump, string nonContiguousBuffersStr) if (!string.IsNullOrEmpty(nonContiguousBuffersStr)) { - provider.LimitAllocatorBufferCapacity().InPixels(1000 * 8); + provider.LimitAllocatorBufferCapacity().InPixels(16_000); } using Image image = provider.GetImage(JpegDecoder); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs index e5f8989c5c..e4fa137191 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs @@ -83,7 +83,7 @@ public void Decode_VerifyRatio(string imagePath, int xResolution, int yResolutio using (var stream = new MemoryStream(testFile.Bytes, false)) { var decoder = new JpegDecoder(); - using (Image image = decoder.Decode(Configuration.Default, stream)) + using (Image image = decoder.Decode(Configuration.Default, stream)) { ImageMetadata meta = image.Metadata; Assert.Equal(xResolution, meta.HorizontalResolution); @@ -130,7 +130,7 @@ public void Decode_VerifyQuality(string imagePath, int quality) var testFile = TestFile.Create(imagePath); using (var stream = new MemoryStream(testFile.Bytes, false)) { - using (Image image = JpegDecoder.Decode(Configuration.Default, stream)) + using (Image image = JpegDecoder.Decode(Configuration.Default, stream)) { JpegMetadata meta = image.Metadata.GetJpegMetadata(); Assert.Equal(quality, meta.Quality); @@ -159,11 +159,11 @@ public void Identify_DetectsCorrectColorType(string imagePath, JpegColorType exp } [Theory] - [WithFile(TestImages.Jpeg.Baseline.Floorplan, PixelTypes.Rgba32, JpegColorType.Luminance)] - [WithFile(TestImages.Jpeg.Baseline.Jpeg420Small, PixelTypes.Rgba32, JpegColorType.YCbCrRatio420)] - [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32, JpegColorType.YCbCrRatio444)] - [WithFile(TestImages.Jpeg.Baseline.JpegRgb, PixelTypes.Rgba32, JpegColorType.Rgb)] - [WithFile(TestImages.Jpeg.Baseline.Cmyk, PixelTypes.Rgba32, JpegColorType.Cmyk)] + [WithFile(TestImages.Jpeg.Baseline.Floorplan, PixelTypes.Rgb24, JpegColorType.Luminance)] + [WithFile(TestImages.Jpeg.Baseline.Jpeg420Small, PixelTypes.Rgb24, JpegColorType.YCbCrRatio420)] + [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgb24, JpegColorType.YCbCrRatio444)] + [WithFile(TestImages.Jpeg.Baseline.JpegRgb, PixelTypes.Rgb24, JpegColorType.Rgb)] + [WithFile(TestImages.Jpeg.Baseline.Cmyk, PixelTypes.Rgb24, JpegColorType.Cmyk)] public void Decode_DetectsCorrectColorType(TestImageProvider provider, JpegColorType expectedColorType) where TPixel : unmanaged, IPixel { diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs index 9beb8358c6..e8533b9bca 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs @@ -15,7 +15,7 @@ public partial class JpegDecoderTests public const string DecodeProgressiveJpegOutputName = "DecodeProgressiveJpeg"; [Theory] - [WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32)] + [WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgb24)] public void DecodeProgressiveJpeg(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -30,17 +30,17 @@ public void DecodeProgressiveJpeg(TestImageProvider provider) } [Theory] - [WithFile(TestImages.Jpeg.Progressive.Progress, PixelTypes.Rgba32)] - public void DecodeProgressiveJpeg_WithLimitedAllocatorBufferCapacity(TestImageProvider provider) + [WithFile(TestImages.Jpeg.Progressive.Progress, PixelTypes.Rgb24)] + public void DecodeProgressiveJpeg_WithLimitedAllocatorBufferCapacity(TestImageProvider provider) { static void RunTest(string providerDump, string nonContiguousBuffersStr) { - TestImageProvider provider = - BasicSerializer.Deserialize>(providerDump); + TestImageProvider provider = + BasicSerializer.Deserialize>(providerDump); provider.LimitAllocatorBufferCapacity().InBytesSqrt(200); - using Image image = provider.GetImage(JpegDecoder); + using Image image = provider.GetImage(JpegDecoder); image.DebugSave(provider, nonContiguousBuffersStr); provider.Utility.TestName = DecodeProgressiveJpegOutputName; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 2a18a2c103..2cbc290273 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Trait("Format", "Jpg")] public partial class JpegDecoderTests { - public const PixelTypes CommonNonDefaultPixelTypes = PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.RgbaVector; + public const PixelTypes CommonNonDefaultPixelTypes = PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.Bgr24 | PixelTypes.RgbaVector; private const float BaselineTolerance = 0.001F / 100; @@ -85,6 +85,14 @@ public void ParseStream_BasicPropertiesAreCorrect() public const string DecodeBaselineJpegOutputName = "DecodeBaselineJpeg"; + [Fact] + public void Decode_NonGeneric_CreatesRgb24Image() + { + string file = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Jpeg.Baseline.Jpeg420Small); + using var image = Image.Load(file); + Assert.IsType>(image); + } + [Theory] [WithFile(TestImages.Jpeg.Baseline.Calliphora, CommonNonDefaultPixelTypes)] public void JpegDecoder_IsNotBoundToSinglePixelType(TestImageProvider provider) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/SpectralToPixelConversionTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/SpectralToPixelConversionTests.cs index 353ae39f0f..f0f92d763e 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/SpectralToPixelConversionTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/SpectralToPixelConversionTests.cs @@ -53,7 +53,7 @@ public void Decoder_PixelBufferComparison(TestImageProvider prov provider.Utility.TestName = JpegDecoderTests.DecodeBaselineJpegOutputName; // Comparison - using (Image image = new Image(Configuration.Default, converter.PixelBuffer, new ImageMetadata())) + using (Image image = new Image(Configuration.Default, converter.GetPixelBuffer(), new ImageMetadata())) using (Image referenceImage = provider.GetReferenceOutputImage(appendPixelTypeToFileName: false)) { ImageSimilarityReport report = ImageComparer.Exact.CompareImagesOrFrames(referenceImage, image); diff --git a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs index 015b3617bc..4e097f3f13 100644 --- a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs +++ b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs @@ -118,6 +118,32 @@ public unsafe void GetRowSpanY(int bufferCapacity, int width, int height, int y, } } + [Theory] + [InlineData(10, 0, 0, 0)] + [InlineData(10, 0, 2, 0)] + [InlineData(10, 1, 2, 0)] + [InlineData(10, 1, 3, 0)] + [InlineData(10, 1, 5, -1)] + [InlineData(10, 2, 2, -1)] + [InlineData(10, 3, 2, 1)] + [InlineData(10, 4, 2, -1)] + [InlineData(30, 3, 2, 0)] + [InlineData(30, 4, 1, -1)] + public void TryGetPaddedRowSpanY(int bufferCapacity, int y, int padding, int expectedBufferIndex) + { + this.MemoryAllocator.BufferCapacityInBytes = bufferCapacity; + using Buffer2D buffer = this.MemoryAllocator.Allocate2D(3, 5); + + bool expectSuccess = expectedBufferIndex >= 0; + bool success = buffer.TryGetPaddedRowSpan(y, padding, out Span paddedSpan); + Xunit.Assert.Equal(expectSuccess, success); + if (success) + { + int expectedSubBufferOffset = (3 * y) - (expectedBufferIndex * buffer.FastMemoryGroup.BufferLength); + Assert.SpanPointsTo(paddedSpan, buffer.FastMemoryGroup[expectedBufferIndex], expectedSubBufferOffset); + } + } + public static TheoryData GetRowSpanY_OutOfRange_Data = new TheoryData() { { Big, 10, 8, -1 }, diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index 42cf1e3c12..3c0faf4991 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -19,9 +19,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public class ResizeTests { private const PixelTypes CommonNonDefaultPixelTypes = - PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.RgbaVector; - - private const PixelTypes DefaultPixelType = PixelTypes.Rgba32; + PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.Bgr24 | PixelTypes.RgbaVector; public static readonly string[] AllResamplerNames = TestUtils.GetAllResamplerNames(); @@ -188,7 +186,7 @@ public void WorksWithDiscoBuffers( } [Theory] - [WithTestPatternImages(100, 100, DefaultPixelType)] + [WithTestPatternImages(100, 100, PixelTypes.Rgba32)] public void Resize_Compand(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -202,8 +200,8 @@ public void Resize_Compand(TestImageProvider provider) } [Theory] - [WithFile(TestImages.Png.Kaboom, DefaultPixelType, false)] - [WithFile(TestImages.Png.Kaboom, DefaultPixelType, true)] + [WithFile(TestImages.Png.Kaboom, PixelTypes.Rgba32, false)] + [WithFile(TestImages.Png.Kaboom, PixelTypes.Rgba32, true)] public void Resize_DoesNotBleedAlphaPixels(TestImageProvider provider, bool compand) where TPixel : unmanaged, IPixel { @@ -217,8 +215,8 @@ public void Resize_DoesNotBleedAlphaPixels(TestImageProvider pro } [Theory] - [WithFile(TestImages.Png.Kaboom, DefaultPixelType, false)] - [WithFile(TestImages.Png.Kaboom, DefaultPixelType, true)] + [WithFile(TestImages.Png.Kaboom, PixelTypes.Rgba32, false)] + [WithFile(TestImages.Png.Kaboom, PixelTypes.Rgba32, true)] public void Resize_PremultiplyAlpha(TestImageProvider provider, bool premultiplyAlpha) where TPixel : unmanaged, IPixel { @@ -243,7 +241,7 @@ public void Resize_PremultiplyAlpha(TestImageProvider provider, } [Theory] - [WithFile(TestImages.Gif.Giphy, DefaultPixelType)] + [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32)] public void Resize_IsAppliedToAllFrames(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -265,7 +263,7 @@ public void Resize_IsNotBoundToSinglePixelType(TestImageProvider } [Theory] - [WithFileCollection(nameof(CommonTestImages), DefaultPixelType)] + [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32)] public void Resize_ThrowsForWrappedMemoryImage(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -283,10 +281,10 @@ public void Resize_ThrowsForWrappedMemoryImage(TestImageProvider } [Theory] - [WithFileCollection(nameof(CommonTestImages), DefaultPixelType, 1)] - [WithFileCollection(nameof(CommonTestImages), DefaultPixelType, 4)] - [WithFileCollection(nameof(CommonTestImages), DefaultPixelType, 8)] - [WithFileCollection(nameof(CommonTestImages), DefaultPixelType, -1)] + [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32 | PixelTypes.Rgb24, 1)] + [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32 | PixelTypes.Rgb24, 4)] + [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32 | PixelTypes.Rgb24, 8)] + [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32 | PixelTypes.Rgb24, -1)] public void Resize_WorksWithAllParallelismLevels( TestImageProvider provider, int maxDegreeOfParallelism) @@ -305,27 +303,27 @@ public void Resize_WorksWithAllParallelismLevels( } [Theory] - [WithFileCollection(nameof(CommonTestImages), nameof(AllResamplerNames), DefaultPixelType, 0.5f, null, null)] + [WithFileCollection(nameof(CommonTestImages), nameof(AllResamplerNames), PixelTypes.Rgba32 | PixelTypes.Rgb24, 0.5f, null, null)] [WithFileCollection( nameof(CommonTestImages), nameof(SmokeTestResamplerNames), - DefaultPixelType, + PixelTypes.Rgba32 | PixelTypes.Rgb24, 0.3f, null, null)] [WithFileCollection( nameof(CommonTestImages), nameof(SmokeTestResamplerNames), - DefaultPixelType, + PixelTypes.Rgba32 | PixelTypes.Rgb24, 1.8f, null, null)] - [WithTestPatternImages(nameof(SmokeTestResamplerNames), 100, 100, DefaultPixelType, 0.5f, null, null)] - [WithTestPatternImages(nameof(SmokeTestResamplerNames), 100, 100, DefaultPixelType, 1f, null, null)] - [WithTestPatternImages(nameof(SmokeTestResamplerNames), 50, 50, DefaultPixelType, 8f, null, null)] - [WithTestPatternImages(nameof(SmokeTestResamplerNames), 201, 199, DefaultPixelType, null, 100, 99)] - [WithTestPatternImages(nameof(SmokeTestResamplerNames), 301, 1180, DefaultPixelType, null, 300, 480)] - [WithTestPatternImages(nameof(SmokeTestResamplerNames), 49, 80, DefaultPixelType, null, 301, 100)] + [WithTestPatternImages(nameof(SmokeTestResamplerNames), 100, 100, PixelTypes.Rgba32, 0.5f, null, null)] + [WithTestPatternImages(nameof(SmokeTestResamplerNames), 100, 100, PixelTypes.Rgba32, 1f, null, null)] + [WithTestPatternImages(nameof(SmokeTestResamplerNames), 50, 50, PixelTypes.Rgba32, 8f, null, null)] + [WithTestPatternImages(nameof(SmokeTestResamplerNames), 201, 199, PixelTypes.Rgba32, null, 100, 99)] + [WithTestPatternImages(nameof(SmokeTestResamplerNames), 301, 1180, PixelTypes.Rgba32, null, 300, 480)] + [WithTestPatternImages(nameof(SmokeTestResamplerNames), 49, 80, PixelTypes.Rgba32, null, 301, 100)] public void Resize_WorksWithAllResamplers( TestImageProvider provider, string samplerName, @@ -382,7 +380,7 @@ public void Resize_WorksWithAllResamplers( } [Theory] - [WithFileCollection(nameof(CommonTestImages), DefaultPixelType)] + [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32 | PixelTypes.Rgb24)] public void ResizeFromSourceRectangle(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -405,12 +403,12 @@ public void ResizeFromSourceRectangle(TestImageProvider provider false)); image.DebugSave(provider); - image.CompareToReferenceOutput(ValidatorComparer, provider); + image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); } } [Theory] - [WithFileCollection(nameof(CommonTestImages), DefaultPixelType)] + [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32 | PixelTypes.Rgb24)] public void ResizeHeightAndKeepAspect(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -419,12 +417,12 @@ public void ResizeHeightAndKeepAspect(TestImageProvider provider image.Mutate(x => x.Resize(0, image.Height / 3, false)); image.DebugSave(provider); - image.CompareToReferenceOutput(ValidatorComparer, provider); + image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); } } [Theory] - [WithTestPatternImages(10, 100, DefaultPixelType)] + [WithTestPatternImages(10, 100, PixelTypes.Rgba32 | PixelTypes.Rgb24)] public void ResizeHeightCannotKeepAspectKeepsOnePixel(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -437,7 +435,7 @@ public void ResizeHeightCannotKeepAspectKeepsOnePixel(TestImageProvider< } [Theory] - [WithFileCollection(nameof(CommonTestImages), DefaultPixelType)] + [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32 | PixelTypes.Rgb24)] public void ResizeWidthAndKeepAspect(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -446,12 +444,12 @@ public void ResizeWidthAndKeepAspect(TestImageProvider provider) image.Mutate(x => x.Resize(image.Width / 3, 0, false)); image.DebugSave(provider); - image.CompareToReferenceOutput(ValidatorComparer, provider); + image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); } } [Theory] - [WithTestPatternImages(100, 10, DefaultPixelType)] + [WithTestPatternImages(100, 10, PixelTypes.Rgba32 | PixelTypes.Rgb24)] public void ResizeWidthCannotKeepAspectKeepsOnePixel(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -464,7 +462,7 @@ public void ResizeWidthCannotKeepAspectKeepsOnePixel(TestImageProvider(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -479,12 +477,12 @@ public void ResizeWithBoxPadMode(TestImageProvider provider) image.Mutate(x => x.Resize(options)); image.DebugSave(provider); - image.CompareToReferenceOutput(ValidatorComparer, provider); + image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); } } [Theory] - [WithFileCollection(nameof(CommonTestImages), DefaultPixelType)] + [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32 | PixelTypes.Rgb24)] public void ResizeWithCropHeightMode(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -495,12 +493,12 @@ public void ResizeWithCropHeightMode(TestImageProvider provider) image.Mutate(x => x.Resize(options)); image.DebugSave(provider); - image.CompareToReferenceOutput(ValidatorComparer, provider); + image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); } } [Theory] - [WithFileCollection(nameof(CommonTestImages), DefaultPixelType)] + [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32 | PixelTypes.Rgb24)] public void ResizeWithCropWidthMode(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -511,12 +509,12 @@ public void ResizeWithCropWidthMode(TestImageProvider provider) image.Mutate(x => x.Resize(options)); image.DebugSave(provider); - image.CompareToReferenceOutput(ValidatorComparer, provider); + image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); } } [Theory] - [WithFile(TestImages.Jpeg.Issues.IncorrectResize1006, DefaultPixelType)] + [WithFile(TestImages.Jpeg.Issues.IncorrectResize1006, PixelTypes.Rgba32 | PixelTypes.Rgb24)] public void CanResizeLargeImageWithCropMode(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -531,12 +529,12 @@ public void CanResizeLargeImageWithCropMode(TestImageProvider pr image.Mutate(x => x.Resize(options)); image.DebugSave(provider); - image.CompareToReferenceOutput(ValidatorComparer, provider); + image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); } } [Theory] - [WithFileCollection(nameof(CommonTestImages), DefaultPixelType)] + [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32 | PixelTypes.Rgb24)] public void ResizeWithMaxMode(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -547,12 +545,12 @@ public void ResizeWithMaxMode(TestImageProvider provider) image.Mutate(x => x.Resize(options)); image.DebugSave(provider); - image.CompareToReferenceOutput(ValidatorComparer, provider); + image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); } } [Theory] - [WithFileCollection(nameof(CommonTestImages), DefaultPixelType)] + [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32 | PixelTypes.Rgb24)] public void ResizeWithMinMode(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -560,21 +558,19 @@ public void ResizeWithMinMode(TestImageProvider provider) { var options = new ResizeOptions { - Size = new Size( - (int)Math.Round(image.Width * .75F), - (int)Math.Round(image.Height * .95F)), + Size = new Size((int)Math.Round(image.Width * .75F), (int)Math.Round(image.Height * .95F)), Mode = ResizeMode.Min }; image.Mutate(x => x.Resize(options)); image.DebugSave(provider); - image.CompareToReferenceOutput(ValidatorComparer, provider); + image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); } } [Theory] - [WithFileCollection(nameof(CommonTestImages), DefaultPixelType)] + [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32 | PixelTypes.Rgb24)] public void ResizeWithPadMode(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -589,12 +585,12 @@ public void ResizeWithPadMode(TestImageProvider provider) image.Mutate(x => x.Resize(options)); image.DebugSave(provider); - image.CompareToReferenceOutput(ValidatorComparer, provider); + image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); } } [Theory] - [WithFileCollection(nameof(CommonTestImages), DefaultPixelType)] + [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32 | PixelTypes.Rgb24)] public void ResizeWithStretchMode(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -609,14 +605,14 @@ public void ResizeWithStretchMode(TestImageProvider provider) image.Mutate(x => x.Resize(options)); image.DebugSave(provider); - image.CompareToReferenceOutput(ValidatorComparer, provider); + image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); } } [Theory] - [WithFile(TestImages.Jpeg.Issues.ExifDecodeOutOfRange694, DefaultPixelType)] - [WithFile(TestImages.Jpeg.Issues.ExifGetString750Transform, DefaultPixelType)] - [WithFile(TestImages.Jpeg.Issues.ExifResize1049, DefaultPixelType)] + [WithFile(TestImages.Jpeg.Issues.ExifDecodeOutOfRange694, PixelTypes.Rgb24)] + [WithFile(TestImages.Jpeg.Issues.ExifGetString750Transform, PixelTypes.Rgb24)] + [WithFile(TestImages.Jpeg.Issues.ExifResize1049, PixelTypes.Rgb24)] public void CanResizeExifIssueImages(TestImageProvider provider) where TPixel : unmanaged, IPixel { diff --git a/tests/Images/External/ReferenceOutput/ResizeTests/CanResizeLargeImageWithCropMode_Rgba32_issue1006-incorrect-resize.png b/tests/Images/External/ReferenceOutput/ResizeTests/CanResizeLargeImageWithCropMode_issue1006-incorrect-resize.png similarity index 100% rename from tests/Images/External/ReferenceOutput/ResizeTests/CanResizeLargeImageWithCropMode_Rgba32_issue1006-incorrect-resize.png rename to tests/Images/External/ReferenceOutput/ResizeTests/CanResizeLargeImageWithCropMode_issue1006-incorrect-resize.png diff --git a/tests/Images/External/ReferenceOutput/ResizeTests/ResizeFromSourceRectangle_Rgba32_CalliphoraPartial.png b/tests/Images/External/ReferenceOutput/ResizeTests/ResizeFromSourceRectangle_CalliphoraPartial.png similarity index 100% rename from tests/Images/External/ReferenceOutput/ResizeTests/ResizeFromSourceRectangle_Rgba32_CalliphoraPartial.png rename to tests/Images/External/ReferenceOutput/ResizeTests/ResizeFromSourceRectangle_CalliphoraPartial.png diff --git a/tests/Images/External/ReferenceOutput/ResizeTests/ResizeHeightAndKeepAspect_Rgba32_CalliphoraPartial.png b/tests/Images/External/ReferenceOutput/ResizeTests/ResizeHeightAndKeepAspect_CalliphoraPartial.png similarity index 100% rename from tests/Images/External/ReferenceOutput/ResizeTests/ResizeHeightAndKeepAspect_Rgba32_CalliphoraPartial.png rename to tests/Images/External/ReferenceOutput/ResizeTests/ResizeHeightAndKeepAspect_CalliphoraPartial.png diff --git a/tests/Images/External/ReferenceOutput/ResizeTests/ResizeWidthAndKeepAspect_Rgba32_CalliphoraPartial.png b/tests/Images/External/ReferenceOutput/ResizeTests/ResizeWidthAndKeepAspect_CalliphoraPartial.png similarity index 100% rename from tests/Images/External/ReferenceOutput/ResizeTests/ResizeWidthAndKeepAspect_Rgba32_CalliphoraPartial.png rename to tests/Images/External/ReferenceOutput/ResizeTests/ResizeWidthAndKeepAspect_CalliphoraPartial.png diff --git a/tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithBoxPadMode_Rgba32_CalliphoraPartial.png b/tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithBoxPadMode_CalliphoraPartial.png similarity index 100% rename from tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithBoxPadMode_Rgba32_CalliphoraPartial.png rename to tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithBoxPadMode_CalliphoraPartial.png diff --git a/tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithCropHeightMode_Rgba32_CalliphoraPartial.png b/tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithCropHeightMode_CalliphoraPartial.png similarity index 100% rename from tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithCropHeightMode_Rgba32_CalliphoraPartial.png rename to tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithCropHeightMode_CalliphoraPartial.png diff --git a/tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithCropWidthMode_Rgba32_CalliphoraPartial.png b/tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithCropWidthMode_CalliphoraPartial.png similarity index 100% rename from tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithCropWidthMode_Rgba32_CalliphoraPartial.png rename to tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithCropWidthMode_CalliphoraPartial.png diff --git a/tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithMaxMode_Rgba32_CalliphoraPartial.png b/tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithMaxMode_CalliphoraPartial.png similarity index 100% rename from tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithMaxMode_Rgba32_CalliphoraPartial.png rename to tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithMaxMode_CalliphoraPartial.png diff --git a/tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithMinMode_Rgba32_CalliphoraPartial.png b/tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithMinMode_CalliphoraPartial.png similarity index 100% rename from tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithMinMode_Rgba32_CalliphoraPartial.png rename to tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithMinMode_CalliphoraPartial.png diff --git a/tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithPadMode_Rgba32_CalliphoraPartial.png b/tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithPadMode_CalliphoraPartial.png similarity index 100% rename from tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithPadMode_Rgba32_CalliphoraPartial.png rename to tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithPadMode_CalliphoraPartial.png diff --git a/tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithStretchMode_Rgba32_CalliphoraPartial.png b/tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithStretchMode_CalliphoraPartial.png similarity index 100% rename from tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithStretchMode_Rgba32_CalliphoraPartial.png rename to tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithStretchMode_CalliphoraPartial.png diff --git a/tests/Images/External/ReferenceOutput/ResizeTests/Resize_IsNotBoundToSinglePixelType_Bgr24_TestPattern50x50.png b/tests/Images/External/ReferenceOutput/ResizeTests/Resize_IsNotBoundToSinglePixelType_Bgr24_TestPattern50x50.png new file mode 100644 index 0000000000..674639d482 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/ResizeTests/Resize_IsNotBoundToSinglePixelType_Bgr24_TestPattern50x50.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4a9940410cca3fe98a6d7aaf0e2184779f908c569a5a34f9965fb3a4f9e6fa8f +size 1066