Browse Source

tests improvements:

- add failing tests for BmpDecoder
- more sophisticated and verbose buffer capacity configurator
af/octree-no-pixelmap
Anton Firszov 6 years ago
parent
commit
1366168a6c
  1. 2
      src/ImageSharp/Advanced/AdvancedImageExtensions.cs
  2. 18
      src/ImageSharp/Formats/Bmp/BmpDecoder.cs
  3. 2
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  4. 2
      src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
  5. 6
      tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs
  6. 33
      tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
  7. 2
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs
  8. 2
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs
  9. 2
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
  10. 2
      tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs
  11. 4
      tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs
  12. 2
      tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs
  13. 35
      tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

2
src/ImageSharp/Advanced/AdvancedImageExtensions.cs

@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp.Advanced
IMemoryGroup<TPixel> mg = source.GetPixelMemoryGroup(); IMemoryGroup<TPixel> mg = source.GetPixelMemoryGroup();
if (mg.Count > 1) if (mg.Count > 1)
{ {
throw new InvalidOperationException($"GetPixelSpan is invalid, since the backing buffer of this {source.Width}x{source.Height} sized image is discontiguos!"); throw new InvalidOperationException($"GetPixelSpan is invalid, since the backing buffer of this {source.Width}x{source.Height} sized image is discontiguous!");
} }
return mg.Single().Span; return mg.Single().Span;

18
src/ImageSharp/Formats/Bmp/BmpDecoder.cs

@ -1,7 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.IO; using System.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Bmp namespace SixLabors.ImageSharp.Formats.Bmp
@ -32,7 +33,20 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{ {
Guard.NotNull(stream, nameof(stream)); Guard.NotNull(stream, nameof(stream));
return new BmpDecoderCore(configuration, this).Decode<TPixel>(stream); var decoder = new BmpDecoderCore(configuration, this);
try
{
return decoder.Decode<TPixel>(stream);
}
catch (InvalidMemoryOperationException ex)
{
Size dims = decoder.Dimensions;
// TODO: use InvalidImageContentException here, if we decide to define it
// https://github.com/SixLabors/ImageSharp/issues/1110
throw new ImageFormatException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}.", ex);
}
} }
/// <inheritdoc /> /// <inheritdoc />

2
src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

@ -114,6 +114,8 @@ namespace SixLabors.ImageSharp.Formats.Bmp
this.options = options; this.options = options;
} }
public Size Dimensions => new Size(this.infoHeader.Width, this.infoHeader.Height);
/// <summary> /// <summary>
/// Decodes the image from the specified this._stream and sets /// Decodes the image from the specified this._stream and sets
/// the data to image. /// the data to image.

2
src/ImageSharp/Formats/Jpeg/JpegDecoder.cs

@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
// TODO: use InvalidImageContentException here, if we decide to define it // TODO: use InvalidImageContentException here, if we decide to define it
// https://github.com/SixLabors/ImageSharp/issues/1110 // https://github.com/SixLabors/ImageSharp/issues/1110
throw new ImageFormatException($"Can not decode the image having degenerate dimensions of {w}x{h}.", ex); throw new ImageFormatException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {w}x{h}.", ex);
} }
} }

6
tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs

@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Tests.Advanced
public void OwnedMemory_PixelDataIsCorrect<TPixel>(TestImageProvider<TPixel> provider) public void OwnedMemory_PixelDataIsCorrect<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
provider.LimitAllocatorBufferCapacity(); provider.LimitAllocatorBufferCapacity().InPixels(200);
using Image<TPixel> image = provider.GetImage(); using Image<TPixel> image = provider.GetImage();
@ -106,7 +106,7 @@ namespace SixLabors.ImageSharp.Tests.Advanced
public void GetPixelRowMemory_PixelDataIsCorrect<TPixel>(TestImageProvider<TPixel> provider) public void GetPixelRowMemory_PixelDataIsCorrect<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
provider.LimitAllocatorBufferCapacity(); provider.LimitAllocatorBufferCapacity().InPixels(200);
using Image<TPixel> image = provider.GetImage(); using Image<TPixel> image = provider.GetImage();
@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Tests.Advanced
public void GetPixelRowSpan_ShouldReferenceSpanOfMemory<TPixel>(TestImageProvider<TPixel> provider) public void GetPixelRowSpan_ShouldReferenceSpanOfMemory<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
provider.LimitAllocatorBufferCapacity(); provider.LimitAllocatorBufferCapacity().InPixels(200);
using Image<TPixel> image = provider.GetImage(); using Image<TPixel> image = provider.GetImage();

33
tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs

@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp
if (!string.IsNullOrEmpty(nonContiguousBuffersStr)) if (!string.IsNullOrEmpty(nonContiguousBuffersStr))
{ {
provider.LimitAllocatorBufferCapacity(); provider.LimitAllocatorBufferCapacity().InPixels(100);
} }
using Image<TPixel> image = provider.GetImage(BmpDecoder); using Image<TPixel> image = provider.GetImage(BmpDecoder);
@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp
public void BmpDecoder_DegenerateMemoryRequest_ShouldTranslateTo_ImageFormatException<TPixel>(TestImageProvider<TPixel> provider) public void BmpDecoder_DegenerateMemoryRequest_ShouldTranslateTo_ImageFormatException<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
provider.LimitAllocatorBufferCapacity(100); provider.LimitAllocatorBufferCapacity().InPixels(10);
ImageFormatException ex = Assert.Throws<ImageFormatException>(provider.GetImage); ImageFormatException ex = Assert.Throws<ImageFormatException>(provider.GetImage);
Assert.IsType<InvalidMemoryOperationException>(ex.InnerException); Assert.IsType<InvalidMemoryOperationException>(ex.InnerException);
} }
@ -253,11 +253,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp
} }
[Theory] [Theory]
[WithFile(RLE8, PixelTypes.Rgba32)] [WithFile(RLE8, PixelTypes.Rgba32, false)]
[WithFile(RLE8Inverted, PixelTypes.Rgba32)] [WithFile(RLE8Inverted, PixelTypes.Rgba32, false)]
public void BmpDecoder_CanDecode_RunLengthEncoded_8Bit<TPixel>(TestImageProvider<TPixel> provider) [WithFile(RLE8, PixelTypes.Rgba32, true)]
[WithFile(RLE8Inverted, PixelTypes.Rgba32, true)]
public void BmpDecoder_CanDecode_RunLengthEncoded_8Bit<TPixel>(TestImageProvider<TPixel> provider, bool enforceDiscontiguousBuffers)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
if (enforceDiscontiguousBuffers)
{
provider.LimitAllocatorBufferCapacity().InBytes(100);
}
using (Image<TPixel> image = provider.GetImage(new BmpDecoder { RleSkippedPixelHandling = RleSkippedPixelHandling.FirstColorOfPalette })) using (Image<TPixel> image = provider.GetImage(new BmpDecoder { RleSkippedPixelHandling = RleSkippedPixelHandling.FirstColorOfPalette }))
{ {
image.DebugSave(provider); image.DebugSave(provider);
@ -266,12 +273,20 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp
} }
[Theory] [Theory]
[WithFile(RLE24, PixelTypes.Rgba32)] [WithFile(RLE24, PixelTypes.Rgba32, false)]
[WithFile(RLE24Cut, PixelTypes.Rgba32)] [WithFile(RLE24Cut, PixelTypes.Rgba32, false)]
[WithFile(RLE24Delta, PixelTypes.Rgba32)] [WithFile(RLE24Delta, PixelTypes.Rgba32, false)]
public void BmpDecoder_CanDecode_RunLengthEncoded_24Bit<TPixel>(TestImageProvider<TPixel> provider) [WithFile(RLE24, PixelTypes.Rgba32, true)]
[WithFile(RLE24Cut, PixelTypes.Rgba32, true)]
[WithFile(RLE24Delta, PixelTypes.Rgba32, true)]
public void BmpDecoder_CanDecode_RunLengthEncoded_24Bit<TPixel>(TestImageProvider<TPixel> provider, bool enforceNonContiguous)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
if (enforceNonContiguous)
{
provider.LimitAllocatorBufferCapacity().InBytes(50);
}
using (Image<TPixel> image = provider.GetImage(new BmpDecoder { RleSkippedPixelHandling = RleSkippedPixelHandling.Black })) using (Image<TPixel> image = provider.GetImage(new BmpDecoder { RleSkippedPixelHandling = RleSkippedPixelHandling.Black }))
{ {
image.DebugSave(provider); image.DebugSave(provider);

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

@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
if (!string.IsNullOrEmpty(nonContiguousBuffersStr)) if (!string.IsNullOrEmpty(nonContiguousBuffersStr))
{ {
provider.LimitAllocatorBufferCapacity(); provider.LimitAllocatorBufferCapacity().InBytes(200);
} }
using Image<TPixel> image = provider.GetImage(JpegDecoder); using Image<TPixel> image = provider.GetImage(JpegDecoder);

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

@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
if (!string.IsNullOrEmpty(nonContiguousBuffersStr)) if (!string.IsNullOrEmpty(nonContiguousBuffersStr))
{ {
provider.LimitAllocatorBufferCapacity(); provider.LimitAllocatorBufferCapacity().InBytes(200);
} }
using Image<TPixel> image = provider.GetImage(JpegDecoder); using Image<TPixel> image = provider.GetImage(JpegDecoder);

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

@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public void DegenerateMemoryRequest_ShouldTranslateTo_ImageFormatException<TPixel>(TestImageProvider<TPixel> provider) public void DegenerateMemoryRequest_ShouldTranslateTo_ImageFormatException<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
provider.LimitAllocatorBufferCapacity(100); provider.LimitAllocatorBufferCapacity().InBytes(10);
ImageFormatException ex = Assert.Throws<ImageFormatException>(provider.GetImage); ImageFormatException ex = Assert.Throws<ImageFormatException>(provider.GetImage);
this.Output.WriteLine(ex.Message); this.Output.WriteLine(ex.Message);
Assert.IsType<InvalidMemoryOperationException>(ex.InnerException); Assert.IsType<InvalidMemoryOperationException>(ex.InnerException);

2
tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs

@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
? ImageComparer.TolerantPercentage(0.1f) ? ImageComparer.TolerantPercentage(0.1f)
: ImageComparer.TolerantPercentage(5f); : ImageComparer.TolerantPercentage(5f);
provider.LimitAllocatorBufferCapacity(); provider.LimitAllocatorBufferCapacity().InBytes(200);
TestJpegEncoderCore(provider, subsample, 100, comparer); TestJpegEncoderCore(provider, subsample, 100, comparer);
} }

4
tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs

@ -204,7 +204,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
public void TgaDecoder_DegenerateMemoryRequest_ShouldTranslateTo_ImageFormatException<TPixel>(TestImageProvider<TPixel> provider) public void TgaDecoder_DegenerateMemoryRequest_ShouldTranslateTo_ImageFormatException<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
provider.LimitAllocatorBufferCapacity(100); provider.LimitAllocatorBufferCapacity().InPixels(10);
ImageFormatException ex = Assert.Throws<ImageFormatException>(provider.GetImage); ImageFormatException ex = Assert.Throws<ImageFormatException>(provider.GetImage);
Assert.IsType<InvalidMemoryOperationException>(ex.InnerException); Assert.IsType<InvalidMemoryOperationException>(ex.InnerException);
} }
@ -219,7 +219,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
{ {
TestImageProvider<TPixel> provider = BasicSerializer.Deserialize<TestImageProvider<TPixel>>(providerDump); TestImageProvider<TPixel> provider = BasicSerializer.Deserialize<TestImageProvider<TPixel>>(providerDump);
provider.LimitAllocatorBufferCapacity(); provider.LimitAllocatorBufferCapacity().InPixels(200);
using Image<TPixel> image = provider.GetImage(new TgaDecoder()); using Image<TPixel> image = provider.GetImage(new TgaDecoder());
image.DebugSave(provider, testOutputDetails: nonContiguousBuffersStr); image.DebugSave(provider, testOutputDetails: nonContiguousBuffersStr);

2
tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs

@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
public void Encode_WorksWithDiscontiguousBuffers<TPixel>(TestImageProvider<TPixel> provider, TgaBitsPerPixel bitsPerPixel) public void Encode_WorksWithDiscontiguousBuffers<TPixel>(TestImageProvider<TPixel> provider, TgaBitsPerPixel bitsPerPixel)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
provider.LimitAllocatorBufferCapacity(10000); provider.LimitAllocatorBufferCapacity().InPixels(100);
TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.RunLength); TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.RunLength);
} }

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

@ -666,13 +666,12 @@ namespace SixLabors.ImageSharp.Tests
} }
} }
internal static void LimitAllocatorBufferCapacity<TPixel>( internal static AllocatorBufferCapacityConfigurator LimitAllocatorBufferCapacity<TPixel>(
this TestImageProvider<TPixel> provider, this TestImageProvider<TPixel> provider)
int bufferCapacityInPixels = 40000) // 200 x 200
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
var allocator = (ArrayPoolMemoryAllocator)provider.Configuration.MemoryAllocator; var allocator = (ArrayPoolMemoryAllocator)provider.Configuration.MemoryAllocator;
allocator.BufferCapacityInBytes = Unsafe.SizeOf<TPixel>() * bufferCapacityInPixels; return new AllocatorBufferCapacityConfigurator(allocator, Unsafe.SizeOf<TPixel>());
} }
internal static Image<Rgba32> ToGrayscaleImage(this Buffer2D<float> buffer, float scale) internal static Image<Rgba32> ToGrayscaleImage(this Buffer2D<float> buffer, float scale)
@ -734,4 +733,32 @@ namespace SixLabors.ImageSharp.Tests
} }
} }
} }
internal class AllocatorBufferCapacityConfigurator
{
private readonly ArrayPoolMemoryAllocator allocator;
private readonly int pixelSizeInBytes;
public AllocatorBufferCapacityConfigurator(ArrayPoolMemoryAllocator allocator, int pixelSizeInBytes)
{
this.allocator = allocator;
this.pixelSizeInBytes = pixelSizeInBytes;
}
/// <summary>
/// Set the maximum buffer capacity to (areaDimensionBytes x areaDimensionBytes) bytes.
/// </summary>
public void InBytes(int areaDimensionBytes)
{
this.allocator.BufferCapacityInBytes = areaDimensionBytes * areaDimensionBytes;
}
/// <summary>
/// Set the maximum buffer capacity to (areaDimensionPixels x areaDimensionPixels x size of the pixel) bytes.
/// </summary>
public void InPixels(int areaDimensionPixels)
{
this.allocator.BufferCapacityInBytes = areaDimensionPixels * areaDimensionPixels * this.pixelSizeInBytes;
}
}
} }

Loading…
Cancel
Save