Browse Source

Decode Jpegs to non-contiguous buffers

af/octree-no-pixelmap
Anton Firszov 6 years ago
parent
commit
d2b99294f7
  1. 2
      src/ImageSharp/ImageFrame{TPixel}.cs
  2. 21
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs
  3. 21
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs
  4. 21
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
  5. 20
      tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs
  6. 11
      tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

2
src/ImageSharp/ImageFrame{TPixel}.cs

@ -133,7 +133,7 @@ namespace SixLabors.ImageSharp
Guard.NotNull(source, nameof(source)); Guard.NotNull(source, nameof(source));
this.PixelBuffer = this.GetConfiguration().MemoryAllocator.Allocate2D<TPixel>(source.PixelBuffer.Width, source.PixelBuffer.Height); this.PixelBuffer = this.GetConfiguration().MemoryAllocator.Allocate2D<TPixel>(source.PixelBuffer.Width, source.PixelBuffer.Height);
source.PixelBuffer.GetSingleSpan().CopyTo(this.PixelBuffer.GetSingleSpan()); source.PixelBuffer.MemoryGroup.CopyTo(this.PixelBuffer.MemoryGroup);
} }
/// <summary> /// <summary>

21
tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs

@ -4,6 +4,7 @@
using Microsoft.DotNet.RemoteExecutor; using Microsoft.DotNet.RemoteExecutor;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using Xunit; using Xunit;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
@ -12,17 +13,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public partial class JpegDecoderTests public partial class JpegDecoderTests
{ {
[Theory] [Theory]
[WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)] [WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32, false)]
public void DecodeBaselineJpeg<TPixel>(TestImageProvider<TPixel> provider) [WithFile(TestImages.Jpeg.Baseline.Calliphora, PixelTypes.Rgba32, true)]
public void DecodeBaselineJpeg<TPixel>(TestImageProvider<TPixel> provider, bool enforceNonContiguousBuffers)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
static void RunTest(string providerDump) static void RunTest(string providerDump, string nonContiguousBuffersStr)
{ {
TestImageProvider<TPixel> provider = TestImageProvider<TPixel> provider =
BasicSerializer.Deserialize<TestImageProvider<TPixel>>(providerDump); BasicSerializer.Deserialize<TestImageProvider<TPixel>>(providerDump);
if (!string.IsNullOrEmpty(nonContiguousBuffersStr))
{
provider.LimitAllocatorBufferCapacity();
}
using Image<TPixel> image = provider.GetImage(JpegDecoder); using Image<TPixel> image = provider.GetImage(JpegDecoder);
image.DebugSave(provider); image.DebugSave(provider, testOutputDetails: nonContiguousBuffersStr);
provider.Utility.TestName = DecodeBaselineJpegOutputName; provider.Utility.TestName = DecodeBaselineJpegOutputName;
image.CompareToReferenceOutput( image.CompareToReferenceOutput(
@ -32,7 +39,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
} }
string providerDump = BasicSerializer.Serialize(provider); string providerDump = BasicSerializer.Serialize(provider);
RemoteExecutor.Invoke(RunTest, providerDump).Dispose(); RemoteExecutor.Invoke(
RunTest,
providerDump,
enforceNonContiguousBuffers ? "NonContiguous" : string.Empty)
.Dispose();
} }
[Theory] [Theory]

21
tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs

@ -14,17 +14,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public const string DecodeProgressiveJpegOutputName = "DecodeProgressiveJpeg"; public const string DecodeProgressiveJpegOutputName = "DecodeProgressiveJpeg";
[Theory] [Theory]
[WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32)] [WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32, false)]
public void DecodeProgressiveJpeg<TPixel>(TestImageProvider<TPixel> provider) [WithFile(TestImages.Jpeg.Progressive.Progress, PixelTypes.Rgba32, true)]
public void DecodeProgressiveJpeg<TPixel>(TestImageProvider<TPixel> provider, bool enforceNonContiguousBuffers)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
static void RunTest(string providerDump) static void RunTest(string providerDump, string nonContiguousBuffersStr)
{ {
TestImageProvider<TPixel> provider = TestImageProvider<TPixel> provider =
BasicSerializer.Deserialize<TestImageProvider<TPixel>>(providerDump); BasicSerializer.Deserialize<TestImageProvider<TPixel>>(providerDump);
if (!string.IsNullOrEmpty(nonContiguousBuffersStr))
{
provider.LimitAllocatorBufferCapacity();
}
using Image<TPixel> image = provider.GetImage(JpegDecoder); using Image<TPixel> image = provider.GetImage(JpegDecoder);
image.DebugSave(provider); image.DebugSave(provider, nonContiguousBuffersStr);
provider.Utility.TestName = DecodeProgressiveJpegOutputName; provider.Utility.TestName = DecodeProgressiveJpegOutputName;
image.CompareToReferenceOutput( image.CompareToReferenceOutput(
@ -33,8 +39,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
appendPixelTypeToFileName: false); appendPixelTypeToFileName: false);
} }
string dump = BasicSerializer.Serialize(provider); string providerDump = BasicSerializer.Serialize(provider);
RemoteExecutor.Invoke(RunTest, dump).Dispose(); RemoteExecutor.Invoke(
RunTest,
providerDump,
enforceNonContiguousBuffers ? "NonContiguous" : string.Empty);
} }
} }
} }

21
tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs

@ -95,19 +95,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public void JpegDecoder_IsNotBoundToSinglePixelType<TPixel>(TestImageProvider<TPixel> provider) public void JpegDecoder_IsNotBoundToSinglePixelType<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
static void RunTest(string providerDump) using Image<TPixel> image = provider.GetImage(JpegDecoder);
{ image.DebugSave(provider);
TestImageProvider<TPixel> provider =
BasicSerializer.Deserialize<TestImageProvider<TPixel>>(providerDump); provider.Utility.TestName = DecodeBaselineJpegOutputName;
using Image<TPixel> image = provider.GetImage(JpegDecoder); image.CompareToReferenceOutput(
image.DebugSave(provider); ImageComparer.Tolerant(BaselineTolerance),
provider,
provider.Utility.TestName = DecodeBaselineJpegOutputName; appendPixelTypeToFileName: false);
image.CompareToReferenceOutput(ImageComparer.Tolerant(BaselineTolerance), provider, appendPixelTypeToFileName: false);
}
string dump = BasicSerializer.Serialize(provider);
RemoteExecutor.Invoke(RunTest, dump).Dispose();
} }
// DEBUG ONLY! // DEBUG ONLY!

20
tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs

@ -22,14 +22,18 @@ namespace SixLabors.ImageSharp.Tests
// are shared between PixelTypes.Color & PixelTypes.Rgba32 // are shared between PixelTypes.Color & PixelTypes.Rgba32
private class Key : IEquatable<Key> private class Key : IEquatable<Key>
{ {
private Tuple<PixelTypes, string, Type> commonValues; private readonly Tuple<PixelTypes, string, Type, int> commonValues;
private Dictionary<string, object> decoderParameters; private readonly Dictionary<string, object> decoderParameters;
public Key(PixelTypes pixelType, string filePath, IImageDecoder customDecoder) public Key(PixelTypes pixelType, string filePath, int allocatorBufferCapacity, IImageDecoder customDecoder)
{ {
Type customType = customDecoder?.GetType(); Type customType = customDecoder?.GetType();
this.commonValues = new Tuple<PixelTypes, string, Type>(pixelType, filePath, customType); this.commonValues = new Tuple<PixelTypes, string, Type, int>(
pixelType,
filePath,
customType,
allocatorBufferCapacity);
this.decoderParameters = GetDecoderParameters(customDecoder); this.decoderParameters = GetDecoderParameters(customDecoder);
} }
@ -147,12 +151,8 @@ namespace SixLabors.ImageSharp.Tests
{ {
Guard.NotNull(decoder, nameof(decoder)); Guard.NotNull(decoder, nameof(decoder));
if (!TestEnvironment.Is64BitProcess) int bufferCapacity = this.Configuration.MemoryAllocator.GetBufferCapacityInBytes();
{ var key = new Key(this.PixelType, this.FilePath, bufferCapacity, decoder);
return this.LoadImage(decoder);
}
var key = new Key(this.PixelType, this.FilePath, decoder);
Image<TPixel> cachedImage = Cache.GetOrAdd(key, _ => this.LoadImage(decoder)); Image<TPixel> cachedImage = Cache.GetOrAdd(key, _ => this.LoadImage(decoder));

11
tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

@ -5,7 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Advanced.ParallelUtils; using SixLabors.ImageSharp.Advanced.ParallelUtils;
using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats;
@ -666,6 +666,15 @@ namespace SixLabors.ImageSharp.Tests
} }
} }
internal static void LimitAllocatorBufferCapacity<TPixel>(
this TestImageProvider<TPixel> provider,
int bufferCapacityInPixels = 40000) // 200 x 200
where TPixel : struct, IPixel<TPixel>
{
var allocator = (ArrayPoolMemoryAllocator)provider.Configuration.MemoryAllocator;
allocator.BufferCapacityInBytes = Unsafe.SizeOf<TPixel>() * bufferCapacityInPixels;
}
internal static Image<Rgba32> ToGrayscaleImage(this Buffer2D<float> buffer, float scale) internal static Image<Rgba32> ToGrayscaleImage(this Buffer2D<float> buffer, float scale)
{ {
var image = new Image<Rgba32>(buffer.Width, buffer.Height); var image = new Image<Rgba32>(buffer.Width, buffer.Height);

Loading…
Cancel
Save