diff --git a/src/ImageSharp/Compression/Zlib/Adler32.cs b/src/ImageSharp/Compression/Zlib/Adler32.cs index 7eb3f4516f..1f3cbbca64 100644 --- a/src/ImageSharp/Compression/Zlib/Adler32.cs +++ b/src/ImageSharp/Compression/Zlib/Adler32.cs @@ -3,6 +3,7 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; #if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; @@ -31,6 +32,8 @@ namespace SixLabors.ImageSharp.Compression.Zlib #if SUPPORTS_RUNTIME_INTRINSICS private const int MinBufferSize = 64; + private const int BlockSize = 1 << 5; + // The C# compiler emits this as a compile-time constant embedded in the PE file. private static ReadOnlySpan Tap1Tap2 => new byte[] { @@ -63,6 +66,11 @@ namespace SixLabors.ImageSharp.Compression.Zlib } #if SUPPORTS_RUNTIME_INTRINSICS + if (Avx2.IsSupported && buffer.Length >= MinBufferSize) + { + return CalculateAvx2(adler, buffer); + } + if (Ssse3.IsSupported && buffer.Length >= MinBufferSize) { return CalculateSse(adler, buffer); @@ -83,19 +91,15 @@ namespace SixLabors.ImageSharp.Compression.Zlib uint s2 = (adler >> 16) & 0xFFFF; // Process the data in blocks. - const int BLOCK_SIZE = 1 << 5; - uint length = (uint)buffer.Length; - uint blocks = length / BLOCK_SIZE; - length -= blocks * BLOCK_SIZE; + uint blocks = length / BlockSize; + length -= blocks * BlockSize; - int index = 0; - fixed (byte* bufferPtr = buffer) + fixed (byte* bufferPtr = &MemoryMarshal.GetReference(buffer)) { - fixed (byte* tapPtr = Tap1Tap2) + fixed (byte* tapPtr = &MemoryMarshal.GetReference(Tap1Tap2)) { - index += (int)blocks * BLOCK_SIZE; - var localBufferPtr = bufferPtr; + byte* localBufferPtr = bufferPtr; // _mm_setr_epi8 on x86 Vector128 tap1 = Sse2.LoadVector128((sbyte*)tapPtr); @@ -105,7 +109,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib while (blocks > 0) { - uint n = NMAX / BLOCK_SIZE; /* The NMAX constraint. */ + uint n = NMAX / BlockSize; /* The NMAX constraint. */ if (n > blocks) { n = blocks; @@ -138,7 +142,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib Vector128 mad2 = Ssse3.MultiplyAddAdjacent(bytes2, tap2); v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad2, ones).AsUInt32()); - localBufferPtr += BLOCK_SIZE; + localBufferPtr += BlockSize; } while (--n > 0); @@ -164,45 +168,127 @@ namespace SixLabors.ImageSharp.Compression.Zlib if (length > 0) { - if (length >= 16) - { - s2 += s1 += localBufferPtr[0]; - s2 += s1 += localBufferPtr[1]; - s2 += s1 += localBufferPtr[2]; - s2 += s1 += localBufferPtr[3]; - s2 += s1 += localBufferPtr[4]; - s2 += s1 += localBufferPtr[5]; - s2 += s1 += localBufferPtr[6]; - s2 += s1 += localBufferPtr[7]; - s2 += s1 += localBufferPtr[8]; - s2 += s1 += localBufferPtr[9]; - s2 += s1 += localBufferPtr[10]; - s2 += s1 += localBufferPtr[11]; - s2 += s1 += localBufferPtr[12]; - s2 += s1 += localBufferPtr[13]; - s2 += s1 += localBufferPtr[14]; - s2 += s1 += localBufferPtr[15]; - - localBufferPtr += 16; - length -= 16; - } + HandleLeftOver(localBufferPtr, length, ref s1, ref s2); + } - while (length-- > 0) - { - s2 += s1 += *localBufferPtr++; - } + return s1 | (s2 << 16); + } + } + } - if (s1 >= BASE) - { - s1 -= BASE; - } + // Based on: https://github.com/zlib-ng/zlib-ng/blob/develop/arch/x86/adler32_avx2.c + [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] + public static unsafe uint CalculateAvx2(uint adler, ReadOnlySpan buffer) + { + uint s1 = adler & 0xFFFF; + uint s2 = (adler >> 16) & 0xFFFF; + uint length = (uint)buffer.Length; - s2 %= BASE; + fixed (byte* bufferPtr = &MemoryMarshal.GetReference(buffer)) + { + byte* localBufferPtr = bufferPtr; + + Vector256 zero = Vector256.Zero; + var dot3v = Vector256.Create((short)1); + var dot2v = Vector256.Create(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + + // Process n blocks of data. At most NMAX data bytes can be + // processed before s2 must be reduced modulo BASE. + var vs1 = Vector256.CreateScalar(s1); + var vs2 = Vector256.CreateScalar(s2); + + while (length >= 32) + { + int k = length < NMAX ? (int)length : (int)NMAX; + k -= k % 32; + length -= (uint)k; + + Vector256 vs10 = vs1; + Vector256 vs3 = Vector256.Zero; + + while (k >= 32) + { + // Load 32 input bytes. + Vector256 block = Avx.LoadVector256(localBufferPtr); + + // Sum of abs diff, resulting in 2 x int32's + Vector256 vs1sad = Avx2.SumAbsoluteDifferences(block, zero); + + vs1 = Avx2.Add(vs1, vs1sad.AsUInt32()); + vs3 = Avx2.Add(vs3, vs10); + + // sum 32 uint8s to 16 shorts. + Vector256 vshortsum2 = Avx2.MultiplyAddAdjacent(block, dot2v); + + // sum 16 shorts to 8 uint32s. + Vector256 vsum2 = Avx2.MultiplyAddAdjacent(vshortsum2, dot3v); + + vs2 = Avx2.Add(vsum2.AsUInt32(), vs2); + vs10 = vs1; + + localBufferPtr += BlockSize; + k -= 32; } - return s1 | (s2 << 16); + // Defer the multiplication with 32 to outside of the loop. + vs3 = Avx2.ShiftLeftLogical(vs3, 5); + vs2 = Avx2.Add(vs2, vs3); + + s1 = (uint)Numerics.EvenReduceSum(vs1.AsInt32()); + s2 = (uint)Numerics.ReduceSum(vs2.AsInt32()); + + s1 %= BASE; + s2 %= BASE; + + vs1 = Vector256.CreateScalar(s1); + vs2 = Vector256.CreateScalar(s2); } + + if (length > 0) + { + HandleLeftOver(localBufferPtr, length, ref s1, ref s2); + } + + return s1 | (s2 << 16); + } + } + + private static unsafe void HandleLeftOver(byte* localBufferPtr, uint length, ref uint s1, ref uint s2) + { + if (length >= 16) + { + s2 += s1 += localBufferPtr[0]; + s2 += s1 += localBufferPtr[1]; + s2 += s1 += localBufferPtr[2]; + s2 += s1 += localBufferPtr[3]; + s2 += s1 += localBufferPtr[4]; + s2 += s1 += localBufferPtr[5]; + s2 += s1 += localBufferPtr[6]; + s2 += s1 += localBufferPtr[7]; + s2 += s1 += localBufferPtr[8]; + s2 += s1 += localBufferPtr[9]; + s2 += s1 += localBufferPtr[10]; + s2 += s1 += localBufferPtr[11]; + s2 += s1 += localBufferPtr[12]; + s2 += s1 += localBufferPtr[13]; + s2 += s1 += localBufferPtr[14]; + s2 += s1 += localBufferPtr[15]; + + localBufferPtr += 16; + length -= 16; } + + while (length-- > 0) + { + s2 += s1 += *localBufferPtr++; + } + + if (s1 >= BASE) + { + s1 -= BASE; + } + + s2 %= BASE; } #endif diff --git a/src/ImageSharp/Compression/Zlib/DeflaterEngine.cs b/src/ImageSharp/Compression/Zlib/DeflaterEngine.cs index 506b0f2c1c..02fa5bf58d 100644 --- a/src/ImageSharp/Compression/Zlib/DeflaterEngine.cs +++ b/src/ImageSharp/Compression/Zlib/DeflaterEngine.cs @@ -483,18 +483,21 @@ namespace SixLabors.ImageSharp.Compression.Zlib int niceLength = Math.Min(this.niceLength, this.lookahead); int matchStrt = this.matchStart; - this.matchLen = Math.Max(this.matchLen, DeflaterConstants.MIN_MATCH - 1); int matchLength = this.matchLen; + matchLength = Math.Max(matchLength, DeflaterConstants.MIN_MATCH - 1); + this.matchLen = matchLength; - if (scan + matchLength > scanMax) + if (scan > scanMax - matchLength) { return false; } + int scanEndPosition = scan + matchLength; + byte* pinnedWindow = this.pinnedWindowPointer; int scanStart = this.strstart; - byte scanEnd1 = pinnedWindow[scan + matchLength - 1]; - byte scanEnd = pinnedWindow[scan + matchLength]; + byte scanEnd1 = pinnedWindow[scanEndPosition - 1]; + byte scanEnd = pinnedWindow[scanEndPosition]; // Do not waste too much time if we already have a good match: if (matchLength >= this.goodLength) @@ -508,8 +511,9 @@ namespace SixLabors.ImageSharp.Compression.Zlib match = curMatch; scan = scanStart; - if (pinnedWindow[match + matchLength] != scanEnd - || pinnedWindow[match + matchLength - 1] != scanEnd1 + int matchEndPosition = match + matchLength; + if (pinnedWindow[matchEndPosition] != scanEnd + || pinnedWindow[matchEndPosition - 1] != scanEnd1 || pinnedWindow[match] != pinnedWindow[scan] || pinnedWindow[++match] != pinnedWindow[++scan]) { @@ -685,6 +689,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib return false; } + const int windowLen = (2 * DeflaterConstants.WSIZE) - DeflaterConstants.MIN_LOOKAHEAD; while (this.lookahead >= DeflaterConstants.MIN_LOOKAHEAD || flush) { if (this.lookahead == 0) @@ -695,7 +700,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib return false; } - if (this.strstart > (2 * DeflaterConstants.WSIZE) - DeflaterConstants.MIN_LOOKAHEAD) + if (this.strstart > windowLen) { // slide window, as FindLongestMatch needs this. // This should only happen when flushing and the window @@ -766,6 +771,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib return false; } + const int windowLen = (2 * DeflaterConstants.WSIZE) - DeflaterConstants.MIN_LOOKAHEAD; while (this.lookahead >= DeflaterConstants.MIN_LOOKAHEAD || flush) { if (this.lookahead == 0) @@ -783,7 +789,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib return false; } - if (this.strstart >= (2 * DeflaterConstants.WSIZE) - DeflaterConstants.MIN_LOOKAHEAD) + if (this.strstart >= windowLen) { // slide window, as FindLongestMatch needs this. // This should only happen when flushing and the window diff --git a/src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs index 8c3edcadfa..ff374a9ac4 100644 --- a/src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. namespace SixLabors.ImageSharp.Processing @@ -34,9 +34,10 @@ namespace SixLabors.ImageSharp.Processing Size = new Size(width, height), Mode = ResizeMode.BoxPad, Sampler = KnownResamplers.NearestNeighbor, + PadColor = color }; - return color.Equals(default) ? source.Resize(options) : source.Resize(options).BackgroundColor(color); + return source.Resize(options); } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs index cc53299528..5c5344ab80 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs @@ -176,9 +176,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Rgba32 rgba = default; color.ToRgba32(ref rgba); - int r = rgba.R >> (8 - IndexBits); - int g = rgba.G >> (8 - IndexBits); - int b = rgba.B >> (8 - IndexBits); + const int shift = 8 - IndexBits; + int r = rgba.R >> shift; + int g = rgba.G >> shift; + int b = rgba.B >> shift; int a = rgba.A >> (8 - IndexAlphaBits); ReadOnlySpan tagSpan = this.tagsOwner.GetSpan(); @@ -413,6 +414,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Span momentSpan = this.momentsOwner.GetSpan(); Span volumeSpan = volume.GetSpan(); Span areaSpan = area.GetSpan(); + const int indexBits2 = IndexBits * 2; + const int indexAndAlphaBits = IndexBits + IndexAlphaBits; + const int indexBitsAndAlphaBits1 = IndexBits + IndexAlphaBits + 1; int baseIndex = GetPaletteIndex(1, 0, 0, 0); for (int r = 1; r < IndexCount; r++) @@ -421,9 +425,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // immediate outer loop. See https://github.com/dotnet/runtime/issues/61420 // To ensure the calculation doesn't happen repeatedly, hoist some of the calculations // in the form of ind1* manually. - int ind1R = (r << ((IndexBits * 2) + IndexAlphaBits)) + - (r << (IndexBits + IndexAlphaBits + 1)) + - (r << (IndexBits * 2)) + + int ind1R = (r << (indexBits2 + IndexAlphaBits)) + + (r << indexBitsAndAlphaBits1) + + (r << indexBits2) + (r << (IndexBits + 1)) + r; @@ -432,7 +436,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization for (int g = 1; g < IndexCount; g++) { int ind1G = ind1R + - (g << (IndexBits + IndexAlphaBits)) + + (g << indexAndAlphaBits) + (g << IndexBits) + g; int r_g = r + g; @@ -446,7 +450,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization b; Moment line = default; - + int bIndexAlphaOffset = b * IndexAlphaCount; for (int a = 1; a < IndexAlphaCount; a++) { int ind1 = ind1B + a; @@ -455,7 +459,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization areaSpan[a] += line; - int inv = (b * IndexAlphaCount) + a; + int inv = bIndexAlphaOffset + a; volumeSpan[inv] += areaSpan[a]; int ind2 = ind1 - baseIndex; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs index 3d69006836..ef6a15fc9f 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs @@ -21,19 +21,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms (Size size, Rectangle rectangle) = ResizeHelper.CalculateTargetLocationAndBounds(sourceSize, options); - this.Sampler = options.Sampler; + this.Options = options; this.DestinationWidth = size.Width; this.DestinationHeight = size.Height; this.DestinationRectangle = rectangle; - this.Compand = options.Compand; - this.PremultiplyAlpha = options.PremultiplyAlpha; } - /// - /// Gets the sampler to perform the resize operation. - /// - public IResampler Sampler { get; } - /// /// Gets the destination width. /// @@ -50,14 +43,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public Rectangle DestinationRectangle { get; } /// - /// Gets a value indicating whether to compress or expand individual pixel color values on processing. - /// - public bool Compand { get; } - - /// - /// Gets a value indicating whether to premultiply the alpha (if it exists) during the resize operation. + /// Gets the resize options. /// - public bool PremultiplyAlpha { get; } + public ResizeOptions Options { get; } /// public override ICloningImageProcessor CreatePixelSpecificCloningProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs index b486e42258..c0bf9291e0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs @@ -4,7 +4,6 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -17,12 +16,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms internal class ResizeProcessor : TransformProcessor, IResamplingTransformImageProcessor where TPixel : unmanaged, IPixel { + private readonly ResizeOptions options; private readonly int destinationWidth; private readonly int destinationHeight; private readonly IResampler resampler; private readonly Rectangle destinationRectangle; - private readonly bool compand; - private readonly bool premultiplyAlpha; private Image destination; public ResizeProcessor(Configuration configuration, ResizeProcessor definition, Image source, Rectangle sourceRectangle) @@ -31,13 +29,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.destinationWidth = definition.DestinationWidth; this.destinationHeight = definition.DestinationHeight; this.destinationRectangle = definition.DestinationRectangle; - this.resampler = definition.Sampler; - this.premultiplyAlpha = definition.PremultiplyAlpha; - this.compand = definition.Compand; + this.options = definition.Options; + this.resampler = definition.Options.Sampler; } /// - protected override Size GetDestinationSize() => new Size(this.destinationWidth, this.destinationHeight); + protected override Size GetDestinationSize() => new(this.destinationWidth, this.destinationHeight); /// protected override void BeforeImageApply(Image destination) @@ -62,8 +59,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Image destination = this.destination; Rectangle sourceRectangle = this.SourceRectangle; Rectangle destinationRectangle = this.destinationRectangle; - bool compand = this.compand; - bool premultiplyAlpha = this.premultiplyAlpha; + bool compand = this.options.Compand; + bool premultiplyAlpha = this.options.PremultiplyAlpha; + bool shouldFill = (this.options.Mode == ResizeMode.BoxPad || this.options.Mode == ResizeMode.Pad) + && this.options.PadColor != default; + TPixel fillColor = this.options.PadColor.ToPixel(); // Handle resize dimensions identical to the original if (source.Width == destination.Width @@ -91,6 +91,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms ImageFrame sourceFrame = source.Frames[i]; ImageFrame destinationFrame = destination.Frames[i]; + if (shouldFill) + { + destinationFrame.Clear(fillColor); + } + ApplyNNResizeFrameTransform( configuration, sourceFrame, @@ -123,6 +128,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms ImageFrame sourceFrame = source.Frames[i]; ImageFrame destinationFrame = destination.Frames[i]; + if (shouldFill) + { + destinationFrame.Clear(fillColor); + } + ApplyResizeFrameTransform( configuration, sourceFrame, diff --git a/src/ImageSharp/Processing/ResizeOptions.cs b/src/ImageSharp/Processing/ResizeOptions.cs index 4b31998da4..62cf8ab239 100644 --- a/src/ImageSharp/Processing/ResizeOptions.cs +++ b/src/ImageSharp/Processing/ResizeOptions.cs @@ -51,5 +51,10 @@ namespace SixLabors.ImageSharp.Processing /// the alpha (if it exists) during the resize operation. /// public bool PremultiplyAlpha { get; set; } = true; + + /// + /// Gets or sets the color to use as a background when padding an image. + /// + public Color PadColor { get; set; } } } diff --git a/tests/ImageSharp.Tests/Formats/Png/Adler32Tests.cs b/tests/ImageSharp.Tests/Formats/Png/Adler32Tests.cs index 0886bd84dc..77f2b76634 100644 --- a/tests/ImageSharp.Tests/Formats/Png/Adler32Tests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/Adler32Tests.cs @@ -3,6 +3,7 @@ using System; using SixLabors.ImageSharp.Compression.Zlib; +using SixLabors.ImageSharp.Tests.TestUtilities; using Xunit; using SharpAdler32 = ICSharpCode.SharpZipLib.Checksum.Adler32; @@ -15,10 +16,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png [InlineData(0)] [InlineData(1)] [InlineData(2)] - public void ReturnsCorrectWhenEmpty(uint input) - { - Assert.Equal(input, Adler32.Calculate(input, default)); - } + public void CalculateAdler_ReturnsCorrectWhenEmpty(uint input) => Assert.Equal(input, Adler32.Calculate(input, default)); [Theory] [InlineData(0)] @@ -28,24 +26,49 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png [InlineData(1024 + 15)] [InlineData(2034)] [InlineData(4096)] - public void MatchesReference(int length) + public void CalculateAdler_MatchesReference(int length) => CalculateAdlerAndCompareToReference(length); + + private static void CalculateAdlerAndCompareToReference(int length) { - var data = GetBuffer(length); + // arrange + byte[] data = GetBuffer(length); var adler = new SharpAdler32(); adler.Update(data); - long expected = adler.Value; + + // act long actual = Adler32.Calculate(data); + // assert Assert.Equal(expected, actual); } private static byte[] GetBuffer(int length) { - var data = new byte[length]; + byte[] data = new byte[length]; new Random(1).NextBytes(data); return data; } + +#if SUPPORTS_RUNTIME_INTRINSICS + [Fact] + public void RunCalculateAdlerTest_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCalculateAdlerTest, HwIntrinsics.AllowAll); + + [Fact] + public void RunCalculateAdlerTest_WithAvxDisabled_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCalculateAdlerTest, HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2); + + [Fact] + public void RunCalculateAdlerTest_WithoutHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCalculateAdlerTest, HwIntrinsics.DisableHWIntrinsic); + + private static void RunCalculateAdlerTest() + { + int[] testData = { 0, 8, 215, 1024, 1024 + 15, 2034, 4096 }; + for (int i = 0; i < testData.Length; i++) + { + CalculateAdlerAndCompareToReference(testData[i]); + } + } +#endif } } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/PadTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/PadTest.cs index b1441d1093..780758c2b4 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/PadTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/PadTest.cs @@ -20,41 +20,37 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public void ImageShouldPad(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage()) - { - image.Mutate(x => x.Pad(image.Width + 50, image.Height + 50)); - image.DebugSave(provider); + using Image image = provider.GetImage(); + image.Mutate(x => x.Pad(image.Width + 50, image.Height + 50)); + image.DebugSave(provider); - // Check pixels are empty - for (int y = 0; y < 25; y++) + // Check pixels are empty + for (int y = 0; y < 25; y++) + { + for (int x = 0; x < 25; x++) { - for (int x = 0; x < 25; x++) - { - Assert.Equal(default, image[x, y]); - } + Assert.Equal(default, image[x, y]); } } } [Theory] - [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32)] + [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32 | PixelTypes.Rgb24)] public void ImageShouldPadWithBackgroundColor(TestImageProvider provider) where TPixel : unmanaged, IPixel { - var color = Color.Red; + Color color = Color.Red; TPixel expected = color.ToPixel(); - using (Image image = provider.GetImage()) - { - image.Mutate(x => x.Pad(image.Width + 50, image.Height + 50, color)); - image.DebugSave(provider); + using Image image = provider.GetImage(); + image.Mutate(x => x.Pad(image.Width + 50, image.Height + 50, color)); + image.DebugSave(provider); - // Check pixels are filled - for (int y = 0; y < 25; y++) + // Check pixels are filled + for (int y = 0; y < 25; y++) + { + for (int x = 0; x < 25; x++) { - for (int x = 0; x < 25; x++) - { - Assert.Equal(expected, image[x, y]); - } + Assert.Equal(expected, image[x, y]); } } } diff --git a/tests/ImageSharp.Tests/Processing/Transforms/PadTest.cs b/tests/ImageSharp.Tests/Processing/Transforms/PadTest.cs index 227e470d4e..3e6726ba06 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/PadTest.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/PadTest.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms Assert.Equal(width, resizeProcessor.DestinationWidth); Assert.Equal(height, resizeProcessor.DestinationHeight); - Assert.Equal(sampler, resizeProcessor.Sampler); + Assert.Equal(sampler, resizeProcessor.Options.Sampler); } } } diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs index 60f7aaa0ba..a29f4c0353 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms Assert.Equal(width, resizeProcessor.DestinationWidth); Assert.Equal(height, resizeProcessor.DestinationHeight); - Assert.Equal(sampler, resizeProcessor.Sampler); + Assert.Equal(sampler, resizeProcessor.Options.Sampler); } [Fact] @@ -52,8 +52,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms Assert.Equal(width, resizeProcessor.DestinationWidth); Assert.Equal(height, resizeProcessor.DestinationHeight); - Assert.Equal(sampler, resizeProcessor.Sampler); - Assert.Equal(compand, resizeProcessor.Compand); + Assert.Equal(sampler, resizeProcessor.Options.Sampler); + Assert.Equal(compand, resizeProcessor.Options.Compand); } [Fact] @@ -78,8 +78,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms Assert.Equal(width, resizeProcessor.DestinationWidth); Assert.Equal(height, resizeProcessor.DestinationHeight); - Assert.Equal(sampler, resizeProcessor.Sampler); - Assert.Equal(compand, resizeProcessor.Compand); + Assert.Equal(sampler, resizeProcessor.Options.Sampler); + Assert.Equal(compand, resizeProcessor.Options.Compand); // Ensure options are not altered. Assert.Equal(width, resizeOptions.Size.Width);