Browse Source

Fix args and add tests

pull/2706/head
James Jackson-South 2 years ago
parent
commit
63d4b2028a
  1. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/ComponentProcessor.cs
  2. 2
      src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs
  3. 3
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  4. 2
      src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
  5. 21
      src/ImageSharp/Memory/Allocators/MemoryAllocator.cs
  6. 4
      src/ImageSharp/Memory/Allocators/MemoryAllocatorOptions.cs
  7. 10
      src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs
  8. 14
      src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs
  9. 13
      src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs
  10. 11
      src/ImageSharp/Memory/InvalidMemoryOperationException.cs
  11. 14
      src/ImageSharp/Memory/MemoryAllocatorExtensions.cs
  12. 2
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs
  13. 2
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs
  14. 9
      tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
  15. 18
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
  16. 16
      tests/ImageSharp.Tests/Memory/Allocators/SimpleGcMemoryAllocatorTests.cs
  17. 13
      tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs
  18. 29
      tests/ImageSharp.Tests/Memory/Buffer2DTests.cs
  19. 12
      tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.Allocate.cs
  20. 2
      tests/ImageSharp.Tests/TestImages.cs
  21. 3
      tests/Images/Input/Bmp/issue-2696.bmp

2
src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/ComponentProcessor.cs

@ -16,7 +16,7 @@ internal abstract class ComponentProcessor : IDisposable
this.Component = component;
this.BlockAreaSize = component.SubSamplingDivisors * blockSize;
this.ColorBuffer = memoryAllocator.Allocate2DOveraligned<float>(
this.ColorBuffer = memoryAllocator.Allocate2DOverAligned<float>(
postProcessorBufferSize.Width,
postProcessorBufferSize.Height,
this.BlockAreaSize.Height);

2
src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs

@ -28,7 +28,7 @@ internal class ComponentProcessor : IDisposable
this.blockAreaSize = component.SubSamplingDivisors * 8;
// alignment of 8 so each block stride can be sampled from a single 'ref pointer'
this.ColorBuffer = memoryAllocator.Allocate2DOveraligned<float>(
this.ColorBuffer = memoryAllocator.Allocate2DOverAligned<float>(
postProcessorBufferSize.Width,
postProcessorBufferSize.Height,
8,

3
src/ImageSharp/Formats/Png/PngDecoderCore.cs

@ -1968,6 +1968,9 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
}
// We rent the buffer here to return it afterwards in Decode()
// We don't want to throw a degenerated memory exception here as we want to allow partial decoding
// so limit the length.
length = (int)Math.Min(length, this.currentStream.Length - this.currentStream.Position);
IMemoryOwner<byte> buffer = this.configuration.MemoryAllocator.Allocate<byte>(length, AllocationOptions.Clean);
this.currentStream.Read(buffer.GetSpan(), 0, length);

2
src/ImageSharp/Formats/Tga/TgaDecoderCore.cs

@ -84,7 +84,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
throw new UnknownImageFormatException("Width or height cannot be 0");
}
Image<TPixel> image = Image.CreateUninitialized<TPixel>(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata);
Image<TPixel> image = new(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata);
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
if (this.fileHeader.ColorMapType == 1)

21
src/ImageSharp/Memory/Allocators/MemoryAllocator.cs

@ -2,7 +2,6 @@
// Licensed under the Six Labors Split License.
using System.Buffers;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Memory;
@ -24,9 +23,7 @@ public abstract class MemoryAllocator
/// </summary>
public static MemoryAllocator Default { get; } = Create();
internal long MemoryGroupAllocationLimitBytes { get; private set; } = Environment.Is64BitProcess ?
4L * OneGigabyte :
OneGigabyte;
internal long MemoryGroupAllocationLimitBytes { get; private set; } = Environment.Is64BitProcess ? 4L * OneGigabyte : OneGigabyte;
internal int SingleBufferAllocationLimitBytes { get; private set; } = OneGigabyte;
@ -82,6 +79,7 @@ public abstract class MemoryAllocator
/// <summary>
/// Allocates a <see cref="MemoryGroup{T}"/>.
/// </summary>
/// <typeparam name="T">The type of element to allocate.</typeparam>
/// <param name="totalLength">The total length of the buffer.</param>
/// <param name="bufferAlignment">The expected alignment (eg. to make sure image rows fit into single buffers).</param>
/// <param name="options">The <see cref="AllocationOptions"/>.</param>
@ -93,22 +91,19 @@ public abstract class MemoryAllocator
AllocationOptions options = AllocationOptions.None)
where T : struct
{
long totalLengthInBytes = totalLength * Unsafe.SizeOf<T>();
if (totalLengthInBytes < 0)
if (totalLength < 0)
{
ThrowNotRepresentable();
InvalidMemoryOperationException.ThrowNegativeAllocationException(totalLength);
}
if (totalLengthInBytes > this.MemoryGroupAllocationLimitBytes)
ulong totalLengthInBytes = (ulong)totalLength * (ulong)Unsafe.SizeOf<T>();
if (totalLengthInBytes > (ulong)this.MemoryGroupAllocationLimitBytes)
{
InvalidMemoryOperationException.ThrowAllocationOverLimitException(totalLengthInBytes, this.MemoryGroupAllocationLimitBytes);
}
return this.AllocateGroupCore<T>(totalLengthInBytes, totalLength, bufferAlignment, options);
[DoesNotReturn]
static void ThrowNotRepresentable() =>
throw new InvalidMemoryOperationException("Attempted to allocate a MemoryGroup of a size that is not representable.");
// Cast to long is safe because we already checked that the total length is within the limit.
return this.AllocateGroupCore<T>(totalLength, (long)totalLengthInBytes, bufferAlignment, options);
}
internal virtual MemoryGroup<T> AllocateGroupCore<T>(long totalLengthInElements, long totalLengthInBytes, int bufferAlignment, AllocationOptions options)

4
src/ImageSharp/Memory/Allocators/MemoryAllocatorOptions.cs

@ -17,7 +17,7 @@ public struct MemoryAllocatorOptions
/// </summary>
public int? MaximumPoolSizeMegabytes
{
get => this.maximumPoolSizeMegabytes;
readonly get => this.maximumPoolSizeMegabytes;
set
{
if (value.HasValue)
@ -35,7 +35,7 @@ public struct MemoryAllocatorOptions
/// </summary>
public int? AllocationLimitMegabytes
{
get => this.allocationLimitMegabytes;
readonly get => this.allocationLimitMegabytes;
set
{
if (value.HasValue)

10
src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs

@ -18,11 +18,13 @@ public sealed class SimpleGcMemoryAllocator : MemoryAllocator
/// <inheritdoc />
public override IMemoryOwner<T> Allocate<T>(int length, AllocationOptions options = AllocationOptions.None)
{
Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));
int lengthInBytes = length * Unsafe.SizeOf<T>();
if (length < 0)
{
InvalidMemoryOperationException.ThrowNegativeAllocationException(length);
}
if (lengthInBytes > this.SingleBufferAllocationLimitBytes)
ulong lengthInBytes = (ulong)length * (ulong)Unsafe.SizeOf<T>();
if (lengthInBytes > (ulong)this.SingleBufferAllocationLimitBytes)
{
InvalidMemoryOperationException.ThrowAllocationOverLimitException(lengthInBytes, this.SingleBufferAllocationLimitBytes);
}

14
src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs

@ -2,7 +2,6 @@
// Licensed under the Six Labors Split License.
using System.Buffers;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory.Internals;
@ -84,15 +83,18 @@ internal sealed class UniformUnmanagedMemoryPoolMemoryAllocator : MemoryAllocato
int length,
AllocationOptions options = AllocationOptions.None)
{
Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));
int lengthInBytes = length * Unsafe.SizeOf<T>();
if (length < 0)
{
InvalidMemoryOperationException.ThrowNegativeAllocationException(length);
}
if (lengthInBytes > this.SingleBufferAllocationLimitBytes)
ulong lengthInBytes = (ulong)length * (ulong)Unsafe.SizeOf<T>();
if (lengthInBytes > (ulong)this.SingleBufferAllocationLimitBytes)
{
InvalidMemoryOperationException.ThrowAllocationOverLimitException(lengthInBytes, this.SingleBufferAllocationLimitBytes);
}
if (lengthInBytes <= this.sharedArrayPoolThresholdInBytes)
if (lengthInBytes <= (ulong)this.sharedArrayPoolThresholdInBytes)
{
var buffer = new SharedArrayPoolBuffer<T>(length);
if (options.Has(AllocationOptions.Clean))
@ -103,7 +105,7 @@ internal sealed class UniformUnmanagedMemoryPoolMemoryAllocator : MemoryAllocato
return buffer;
}
if (lengthInBytes <= this.poolBufferSizeInBytes)
if (lengthInBytes <= (ulong)this.poolBufferSizeInBytes)
{
UnmanagedMemoryHandle mem = this.pool.Rent();
if (mem.IsValid)

13
src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs

@ -83,15 +83,16 @@ internal abstract partial class MemoryGroup<T> : IMemoryGroup<T>, IDisposable
{
int bufferCapacityInBytes = allocator.GetBufferCapacityInBytes();
Guard.NotNull(allocator, nameof(allocator));
Guard.MustBeGreaterThanOrEqualTo(totalLengthInElements, 0, nameof(totalLengthInElements));
Guard.MustBeGreaterThanOrEqualTo(bufferAlignmentInElements, 0, nameof(bufferAlignmentInElements));
int blockCapacityInElements = bufferCapacityInBytes / ElementSize;
if (totalLengthInElements < 0)
{
InvalidMemoryOperationException.ThrowNegativeAllocationException(totalLengthInElements);
}
if (bufferAlignmentInElements > blockCapacityInElements)
int blockCapacityInElements = bufferCapacityInBytes / ElementSize;
if (bufferAlignmentInElements < 0 || bufferAlignmentInElements > blockCapacityInElements)
{
throw new InvalidMemoryOperationException(
$"The buffer capacity of the provided MemoryAllocator is insufficient for the requested buffer alignment: {bufferAlignmentInElements}.");
InvalidMemoryOperationException.ThrowInvalidAlignmentException(bufferAlignmentInElements);
}
if (totalLengthInElements == 0)

11
src/ImageSharp/Memory/InvalidMemoryOperationException.cs

@ -28,6 +28,15 @@ public class InvalidMemoryOperationException : InvalidOperationException
}
[DoesNotReturn]
internal static void ThrowAllocationOverLimitException(long length, long limit) =>
internal static void ThrowNegativeAllocationException(long length) =>
throw new InvalidMemoryOperationException($"Attempted to allocate a buffer of negative length={length}.");
[DoesNotReturn]
internal static void ThrowInvalidAlignmentException(long alignment) =>
throw new InvalidMemoryOperationException(
$"The buffer capacity of the provided MemoryAllocator is insufficient for the requested buffer alignment: {alignment}.");
[DoesNotReturn]
internal static void ThrowAllocationOverLimitException(ulong length, long limit) =>
throw new InvalidMemoryOperationException($"Attempted to allocate a buffer of length={length} that exceeded the limit {limit}.");
}

14
src/ImageSharp/Memory/MemoryAllocatorExtensions.cs

@ -18,20 +18,20 @@ public static class MemoryAllocatorExtensions
/// <param name="memoryAllocator">The memory allocator.</param>
/// <param name="width">The buffer width.</param>
/// <param name="height">The buffer height.</param>
/// <param name="preferContiguosImageBuffers">A value indicating whether the allocated buffer should be contiguous, unless bigger than <see cref="int.MaxValue"/>.</param>
/// <param name="preferContiguousImageBuffers">A value indicating whether the allocated buffer should be contiguous, unless bigger than <see cref="int.MaxValue"/>.</param>
/// <param name="options">The allocation options.</param>
/// <returns>The <see cref="Buffer2D{T}"/>.</returns>
public static Buffer2D<T> Allocate2D<T>(
this MemoryAllocator memoryAllocator,
int width,
int height,
bool preferContiguosImageBuffers,
bool preferContiguousImageBuffers,
AllocationOptions options = AllocationOptions.None)
where T : struct
{
long groupLength = (long)width * height;
MemoryGroup<T> memoryGroup;
if (preferContiguosImageBuffers && groupLength < int.MaxValue)
if (preferContiguousImageBuffers && groupLength < int.MaxValue)
{
IMemoryOwner<T> buffer = memoryAllocator.Allocate<T>((int)groupLength, options);
memoryGroup = MemoryGroup<T>.CreateContiguous(buffer, false);
@ -69,16 +69,16 @@ public static class MemoryAllocatorExtensions
/// <typeparam name="T">The type of buffer items to allocate.</typeparam>
/// <param name="memoryAllocator">The memory allocator.</param>
/// <param name="size">The buffer size.</param>
/// <param name="preferContiguosImageBuffers">A value indicating whether the allocated buffer should be contiguous, unless bigger than <see cref="int.MaxValue"/>.</param>
/// <param name="preferContiguousImageBuffers">A value indicating whether the allocated buffer should be contiguous, unless bigger than <see cref="int.MaxValue"/>.</param>
/// <param name="options">The allocation options.</param>
/// <returns>The <see cref="Buffer2D{T}"/>.</returns>
public static Buffer2D<T> Allocate2D<T>(
this MemoryAllocator memoryAllocator,
Size size,
bool preferContiguosImageBuffers,
bool preferContiguousImageBuffers,
AllocationOptions options = AllocationOptions.None)
where T : struct =>
Allocate2D<T>(memoryAllocator, size.Width, size.Height, preferContiguosImageBuffers, options);
Allocate2D<T>(memoryAllocator, size.Width, size.Height, preferContiguousImageBuffers, options);
/// <summary>
/// Allocates a buffer of value type objects interpreted as a 2D region
@ -96,7 +96,7 @@ public static class MemoryAllocatorExtensions
where T : struct =>
Allocate2D<T>(memoryAllocator, size.Width, size.Height, false, options);
internal static Buffer2D<T> Allocate2DOveraligned<T>(
internal static Buffer2D<T> Allocate2DOverAligned<T>(
this MemoryAllocator memoryAllocator,
int width,
int height,

2
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs

@ -50,7 +50,7 @@ internal partial class ResizeKernelMap : IDisposable
this.sourceLength = sourceLength;
this.DestinationLength = destinationLength;
this.MaxDiameter = (radius * 2) + 1;
this.data = memoryAllocator.Allocate2D<float>(this.MaxDiameter, bufferHeight, preferContiguosImageBuffers: true, AllocationOptions.Clean);
this.data = memoryAllocator.Allocate2D<float>(this.MaxDiameter, bufferHeight, preferContiguousImageBuffers: true, AllocationOptions.Clean);
this.pinHandle = this.data.DangerousGetSingleMemory().Pin();
this.kernels = new ResizeKernel[destinationLength];
this.tempValues = new double[this.MaxDiameter];

2
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs

@ -83,7 +83,7 @@ internal sealed class ResizeWorker<TPixel> : IDisposable
this.transposedFirstPassBuffer = configuration.MemoryAllocator.Allocate2D<Vector4>(
this.workerHeight,
targetWorkingRect.Width,
preferContiguosImageBuffers: true,
preferContiguousImageBuffers: true,
options: AllocationOptions.Clean);
this.tempRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(this.sourceRectangle.Width);

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

@ -558,4 +558,13 @@ public class BmpDecoderTests
// Compare to reference output instead.
image.CompareToReferenceOutput(provider, extension: "png");
}
[Theory]
[WithFile(Issue2696, PixelTypes.Rgba32)]
public void BmpDecoder_ThrowsException_Issue2696<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
=> Assert.Throws<InvalidImageContentException>(() =>
{
using Image<TPixel> image = provider.GetImage(BmpDecoder.Instance);
});
}

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

@ -338,21 +338,11 @@ public partial class JpegDecoderTests
}
[Theory]
[WithFile(TestImages.Jpeg.Issues.HangBadScan, PixelTypes.L8)]
public void DecodeHang<TPixel>(TestImageProvider<TPixel> provider)
[WithFile(TestImages.Jpeg.Issues.HangBadScan, PixelTypes.Rgb24)]
public void DecodeHang_ThrowsException<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
if (TestEnvironment.IsWindows &&
TestEnvironment.RunsOnCI)
{
// Windows CI runs consistently fail with OOM.
return;
}
using Image<TPixel> image = provider.GetImage(JpegDecoder.Instance);
Assert.Equal(65503, image.Width);
Assert.Equal(65503, image.Height);
}
=> Assert.Throws<InvalidImageContentException>(
() => { using Image<TPixel> image = provider.GetImage(JpegDecoder.Instance); });
// https://github.com/SixLabors/ImageSharp/issues/2517
[Theory]

16
tests/ImageSharp.Tests/Memory/Allocators/SimpleGcMemoryAllocatorTests.cs

@ -19,13 +19,17 @@ public class SimpleGcMemoryAllocatorTests
protected SimpleGcMemoryAllocator MemoryAllocator { get; } = new SimpleGcMemoryAllocator();
[Theory]
[InlineData(-1)]
public void Allocate_IncorrectAmount_ThrowsCorrect_ArgumentOutOfRangeException(int length)
public static TheoryData<int> InvalidLengths { get; set; } = new()
{
ArgumentOutOfRangeException ex = Assert.Throws<ArgumentOutOfRangeException>(() => this.MemoryAllocator.Allocate<BigStruct>(length));
Assert.Equal("length", ex.ParamName);
}
{ -1 },
{ (1 << 30) + 1 }
};
[Theory]
[MemberData(nameof(InvalidLengths))]
public void Allocate_IncorrectAmount_ThrowsCorrect_InvalidMemoryOperationException(int length)
=> Assert.Throws<InvalidMemoryOperationException>(
() => this.MemoryAllocator.Allocate<BigStruct>(length));
[Fact]
public unsafe void Allocate_MemoryIsPinnableMultipleTimes()

13
tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs

@ -111,9 +111,20 @@ public class UniformUnmanagedPoolMemoryAllocatorTests
public void AllocateGroup_SizeInBytesOverLongMaxValue_ThrowsInvalidMemoryOperationException()
{
var allocator = new UniformUnmanagedMemoryPoolMemoryAllocator(null);
Assert.Throws<InvalidMemoryOperationException>(() => allocator.AllocateGroup<S4>(int.MaxValue * (long)int.MaxValue, int.MaxValue));
Assert.Throws<InvalidMemoryOperationException>(() => allocator.AllocateGroup<byte>(int.MaxValue * (long)int.MaxValue, int.MaxValue));
}
public static TheoryData<int> InvalidLengths { get; set; } = new()
{
{ -1 },
{ (1 << 30) + 1 }
};
[Theory]
[MemberData(nameof(InvalidLengths))]
public void Allocate_IncorrectAmount_ThrowsCorrect_InvalidMemoryOperationException(int length)
=> Assert.Throws<InvalidMemoryOperationException>(() => new UniformUnmanagedMemoryPoolMemoryAllocator(null).Allocate<S512>(length));
[Fact]
public unsafe void Allocate_MemoryIsPinnableMultipleTimes()
{

29
tests/ImageSharp.Tests/Memory/Buffer2DTests.cs

@ -4,6 +4,7 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests.Memory;
@ -72,11 +73,11 @@ public partial class Buffer2DTests
using Buffer2D<byte> buffer = useSizeOverload ?
this.MemoryAllocator.Allocate2D<byte>(
new Size(200, 200),
preferContiguosImageBuffers: true) :
preferContiguousImageBuffers: true) :
this.MemoryAllocator.Allocate2D<byte>(
200,
200,
preferContiguosImageBuffers: true);
preferContiguousImageBuffers: true);
Assert.Equal(1, buffer.FastMemoryGroup.Count);
Assert.Equal(200 * 200, buffer.FastMemoryGroup.TotalLength);
}
@ -87,7 +88,7 @@ public partial class Buffer2DTests
{
this.MemoryAllocator.BufferCapacityInBytes = sizeof(int) * bufferCapacity;
using Buffer2D<int> buffer = this.MemoryAllocator.Allocate2DOveraligned<int>(width, height, alignmentMultiplier);
using Buffer2D<int> buffer = this.MemoryAllocator.Allocate2DOverAligned<int>(width, height, alignmentMultiplier);
MemoryGroup<int> memoryGroup = buffer.FastMemoryGroup;
int expectedAlignment = width * alignmentMultiplier;
@ -337,4 +338,26 @@ public partial class Buffer2DTests
Assert.False(mgBefore.IsValid);
Assert.NotSame(mgBefore, buffer1.MemoryGroup);
}
public static TheoryData<Size> InvalidLengths { get; set; } = new()
{
{ new(-1, -1) },
{ new(32768, 32769) },
{ new(32769, 32768) }
};
[Theory]
[MemberData(nameof(InvalidLengths))]
public void Allocate_IncorrectAmount_ThrowsCorrect_InvalidMemoryOperationException(Size size)
=> Assert.Throws<InvalidMemoryOperationException>(() => this.MemoryAllocator.Allocate2D<Rgba32>(size.Width, size.Height));
[Theory]
[MemberData(nameof(InvalidLengths))]
public void Allocate_IncorrectAmount_ThrowsCorrect_InvalidMemoryOperationException_Size(Size size)
=> Assert.Throws<InvalidMemoryOperationException>(() => this.MemoryAllocator.Allocate2D<Rgba32>(new Size(size)));
[Theory]
[MemberData(nameof(InvalidLengths))]
public void Allocate_IncorrectAmount_ThrowsCorrect_InvalidMemoryOperationException_OverAligned(Size size)
=> Assert.Throws<InvalidMemoryOperationException>(() => this.MemoryAllocator.Allocate2DOverAligned<Rgba32>(size.Width, size.Height, 1));
}

12
tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.Allocate.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
@ -219,11 +219,17 @@ public partial class MemoryGroupTests
[StructLayout(LayoutKind.Sequential, Size = 5)]
internal struct S5
{
public override string ToString() => "S5";
public override readonly string ToString() => nameof(S5);
}
[StructLayout(LayoutKind.Sequential, Size = 4)]
internal struct S4
{
public override string ToString() => "S4";
public override readonly string ToString() => nameof(S4);
}
[StructLayout(LayoutKind.Explicit, Size = 512)]
internal struct S512
{
public override readonly string ToString() => nameof(S512);
}

2
tests/ImageSharp.Tests/TestImages.cs

@ -439,6 +439,8 @@ public static class TestImages
public const string Rgba321010102 = "Bmp/rgba32-1010102.bmp";
public const string RgbaAlphaBitfields = "Bmp/rgba32abf.bmp";
public const string Issue2696 = "Bmp/issue-2696.bmp";
public const string BlackWhitePalletDataMatrix = "Bmp/bit1datamatrix.bmp";
public static readonly string[] BitFields =

3
tests/Images/Input/Bmp/issue-2696.bmp

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:de7e7ec0454a55f6a76c859f356b240a3d4cb56ca50dfa209a1813dd09e12076
size 143
Loading…
Cancel
Save