From d2b99294f75d50fc2c6dcb3c0eb2a2f6e4e4d0f7 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 5 Feb 2020 00:50:35 +0100 Subject: [PATCH] Decode Jpegs to non-contiguous buffers --- src/ImageSharp/ImageFrame{TPixel}.cs | 2 +- .../Formats/Jpg/JpegDecoderTests.Baseline.cs | 21 ++++++++++++++----- .../Jpg/JpegDecoderTests.Progressive.cs | 21 +++++++++++++------ .../Formats/Jpg/JpegDecoderTests.cs | 21 +++++++------------ .../ImageProviders/FileProvider.cs | 20 +++++++++--------- .../TestUtilities/TestImageExtensions.cs | 11 +++++++++- 6 files changed, 60 insertions(+), 36 deletions(-) diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index abeb00f74..bc45a45fd 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -133,7 +133,7 @@ namespace SixLabors.ImageSharp Guard.NotNull(source, nameof(source)); this.PixelBuffer = this.GetConfiguration().MemoryAllocator.Allocate2D(source.PixelBuffer.Width, source.PixelBuffer.Height); - source.PixelBuffer.GetSingleSpan().CopyTo(this.PixelBuffer.GetSingleSpan()); + source.PixelBuffer.MemoryGroup.CopyTo(this.PixelBuffer.MemoryGroup); } /// diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs index 628f59a9a..69c0aa87a 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs @@ -4,6 +4,7 @@ using Microsoft.DotNet.RemoteExecutor; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.TestUtilities; +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; // ReSharper disable InconsistentNaming @@ -12,17 +13,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public partial class JpegDecoderTests { [Theory] - [WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)] - public void DecodeBaselineJpeg(TestImageProvider provider) + [WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32, false)] + [WithFile(TestImages.Jpeg.Baseline.Calliphora, PixelTypes.Rgba32, true)] + public void DecodeBaselineJpeg(TestImageProvider provider, bool enforceNonContiguousBuffers) where TPixel : struct, IPixel { - static void RunTest(string providerDump) + static void RunTest(string providerDump, string nonContiguousBuffersStr) { TestImageProvider provider = BasicSerializer.Deserialize>(providerDump); + if (!string.IsNullOrEmpty(nonContiguousBuffersStr)) + { + provider.LimitAllocatorBufferCapacity(); + } + using Image image = provider.GetImage(JpegDecoder); - image.DebugSave(provider); + image.DebugSave(provider, testOutputDetails: nonContiguousBuffersStr); provider.Utility.TestName = DecodeBaselineJpegOutputName; image.CompareToReferenceOutput( @@ -32,7 +39,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } string providerDump = BasicSerializer.Serialize(provider); - RemoteExecutor.Invoke(RunTest, providerDump).Dispose(); + RemoteExecutor.Invoke( + RunTest, + providerDump, + enforceNonContiguousBuffers ? "NonContiguous" : string.Empty) + .Dispose(); } [Theory] diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs index 886cef7ac..33bf64bb4 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs @@ -14,17 +14,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public const string DecodeProgressiveJpegOutputName = "DecodeProgressiveJpeg"; [Theory] - [WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32)] - public void DecodeProgressiveJpeg(TestImageProvider provider) + [WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32, false)] + [WithFile(TestImages.Jpeg.Progressive.Progress, PixelTypes.Rgba32, true)] + public void DecodeProgressiveJpeg(TestImageProvider provider, bool enforceNonContiguousBuffers) where TPixel : struct, IPixel { - static void RunTest(string providerDump) + static void RunTest(string providerDump, string nonContiguousBuffersStr) { TestImageProvider provider = BasicSerializer.Deserialize>(providerDump); + if (!string.IsNullOrEmpty(nonContiguousBuffersStr)) + { + provider.LimitAllocatorBufferCapacity(); + } + using Image image = provider.GetImage(JpegDecoder); - image.DebugSave(provider); + image.DebugSave(provider, nonContiguousBuffersStr); provider.Utility.TestName = DecodeProgressiveJpegOutputName; image.CompareToReferenceOutput( @@ -33,8 +39,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg appendPixelTypeToFileName: false); } - string dump = BasicSerializer.Serialize(provider); - RemoteExecutor.Invoke(RunTest, dump).Dispose(); + string providerDump = BasicSerializer.Serialize(provider); + RemoteExecutor.Invoke( + RunTest, + providerDump, + enforceNonContiguousBuffers ? "NonContiguous" : string.Empty); } } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 09e98b5c4..d829b5f98 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -95,19 +95,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public void JpegDecoder_IsNotBoundToSinglePixelType(TestImageProvider provider) where TPixel : struct, IPixel { - static void RunTest(string providerDump) - { - TestImageProvider provider = - BasicSerializer.Deserialize>(providerDump); - using Image image = provider.GetImage(JpegDecoder); - image.DebugSave(provider); - - provider.Utility.TestName = DecodeBaselineJpegOutputName; - image.CompareToReferenceOutput(ImageComparer.Tolerant(BaselineTolerance), provider, appendPixelTypeToFileName: false); - } - - string dump = BasicSerializer.Serialize(provider); - RemoteExecutor.Invoke(RunTest, dump).Dispose(); + using Image image = provider.GetImage(JpegDecoder); + image.DebugSave(provider); + + provider.Utility.TestName = DecodeBaselineJpegOutputName; + image.CompareToReferenceOutput( + ImageComparer.Tolerant(BaselineTolerance), + provider, + appendPixelTypeToFileName: false); } // DEBUG ONLY! diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs index 4dd6ab655..0427b3732 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs @@ -22,14 +22,18 @@ namespace SixLabors.ImageSharp.Tests // are shared between PixelTypes.Color & PixelTypes.Rgba32 private class Key : IEquatable { - private Tuple commonValues; + private readonly Tuple commonValues; - private Dictionary decoderParameters; + private readonly Dictionary decoderParameters; - public Key(PixelTypes pixelType, string filePath, IImageDecoder customDecoder) + public Key(PixelTypes pixelType, string filePath, int allocatorBufferCapacity, IImageDecoder customDecoder) { Type customType = customDecoder?.GetType(); - this.commonValues = new Tuple(pixelType, filePath, customType); + this.commonValues = new Tuple( + pixelType, + filePath, + customType, + allocatorBufferCapacity); this.decoderParameters = GetDecoderParameters(customDecoder); } @@ -147,12 +151,8 @@ namespace SixLabors.ImageSharp.Tests { Guard.NotNull(decoder, nameof(decoder)); - if (!TestEnvironment.Is64BitProcess) - { - return this.LoadImage(decoder); - } - - var key = new Key(this.PixelType, this.FilePath, decoder); + int bufferCapacity = this.Configuration.MemoryAllocator.GetBufferCapacityInBytes(); + var key = new Key(this.PixelType, this.FilePath, bufferCapacity, decoder); Image cachedImage = Cache.GetOrAdd(key, _ => this.LoadImage(decoder)); diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index 8cf53bf85..d4c2dc307 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Numerics; - +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced.ParallelUtils; using SixLabors.ImageSharp.Formats; @@ -666,6 +666,15 @@ namespace SixLabors.ImageSharp.Tests } } + internal static void LimitAllocatorBufferCapacity( + this TestImageProvider provider, + int bufferCapacityInPixels = 40000) // 200 x 200 + where TPixel : struct, IPixel + { + var allocator = (ArrayPoolMemoryAllocator)provider.Configuration.MemoryAllocator; + allocator.BufferCapacityInBytes = Unsafe.SizeOf() * bufferCapacityInPixels; + } + internal static Image ToGrayscaleImage(this Buffer2D buffer, float scale) { var image = new Image(buffer.Width, buffer.Height);