Browse Source

Allow decoding Tiff of different frame size.

pull/2788/head
James Jackson-South 2 years ago
parent
commit
eb5c05efe1
  1. 2
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  2. 2
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  3. 103
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
  4. 4
      src/ImageSharp/Formats/Webp/WebpEncoderCore.cs
  5. 2
      src/ImageSharp/Image.cs
  6. 20
      src/ImageSharp/ImageFrame.cs
  7. 2
      src/ImageSharp/ImageFrameCollection{TPixel}.cs
  8. 2
      src/ImageSharp/ImageFrame{TPixel}.cs
  9. 4
      src/ImageSharp/Image{TPixel}.cs
  10. 4
      src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs
  11. 2
      src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs
  12. 2
      src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs
  13. 2
      src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs
  14. 11
      tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
  15. 1
      tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderMultiframeTests.cs
  16. 3
      tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs
  17. 3
      tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs

2
src/ImageSharp/Formats/Gif/GifEncoderCore.cs

@ -209,7 +209,7 @@ internal sealed class GifEncoderCore
ImageFrame<TPixel> previousFrame = image.Frames.RootFrame;
// This frame is reused to store de-duplicated pixel buffers.
using ImageFrame<TPixel> encodingFrame = new(previousFrame.Configuration, previousFrame.Size());
using ImageFrame<TPixel> encodingFrame = new(previousFrame.Configuration, previousFrame.Size);
for (int i = 1; i < image.Frames.Count; i++)
{

2
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -231,7 +231,7 @@ internal sealed class PngEncoderCore : IDisposable
ImageFrame<TPixel> previousFrame = image.Frames.RootFrame;
// This frame is reused to store de-duplicated pixel buffers.
using ImageFrame<TPixel> encodingFrame = new(image.Configuration, previousFrame.Size());
using ImageFrame<TPixel> encodingFrame = new(image.Configuration, previousFrame.Size);
for (; currentFrameIndex < image.Frames.Count; currentFrameIndex++)
{

103
src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs

@ -167,11 +167,18 @@ internal class TiffDecoderCore : ImageDecoderCore
this.byteOrder = reader.ByteOrder;
this.isBigTiff = reader.IsBigTiff;
Size? size = null;
uint frameCount = 0;
foreach (ExifProfile ifd in directories)
{
cancellationToken.ThrowIfCancellationRequested();
ImageFrame<TPixel> frame = this.DecodeFrame<TPixel>(ifd, cancellationToken);
ImageFrame<TPixel> frame = this.DecodeFrame<TPixel>(ifd, size, cancellationToken);
if (!size.HasValue)
{
size = frame.Size;
}
frames.Add(frame);
framesMetadata.Add(frame.Metadata);
@ -181,19 +188,8 @@ internal class TiffDecoderCore : ImageDecoderCore
}
}
this.Dimensions = frames[0].Size;
ImageMetadata metadata = TiffDecoderMetadataCreator.Create(framesMetadata, this.skipMetadata, reader.ByteOrder, reader.IsBigTiff);
// TODO: Tiff frames can have different sizes.
ImageFrame<TPixel> root = frames[0];
this.Dimensions = root.Size();
foreach (ImageFrame<TPixel> frame in frames)
{
if (frame.Size() != root.Size())
{
TiffThrowHelper.ThrowNotSupported("Images with different sizes are not supported");
}
}
return new Image<TPixel>(this.configuration, metadata, frames);
}
catch
@ -235,9 +231,10 @@ internal class TiffDecoderCore : ImageDecoderCore
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="tags">The IFD tags.</param>
/// <param name="size">The previously determined root frame size if decoded.</param>
/// <param name="cancellationToken">The token to monitor cancellation.</param>
/// <returns>The tiff frame.</returns>
private ImageFrame<TPixel> DecodeFrame<TPixel>(ExifProfile tags, CancellationToken cancellationToken)
private ImageFrame<TPixel> DecodeFrame<TPixel>(ExifProfile tags, Size? size, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
ImageFrameMetadata imageFrameMetaData = this.CreateFrameMetadata(tags);
@ -245,15 +242,29 @@ internal class TiffDecoderCore : ImageDecoderCore
int width = GetImageWidth(tags);
int height = GetImageHeight(tags);
ImageFrame<TPixel> frame = new(this.configuration, width, height, imageFrameMetaData);
// If size has a value and the width/height off the tiff is smaller we much capture the delta.
if (size.HasValue)
{
if (size.Value.Width < width || size.Value.Height < height)
{
TiffThrowHelper.ThrowNotSupported("Images with frames of size greater than the root frame are not supported.");
}
}
else
{
size = new Size(width, height);
}
ImageFrame<TPixel> frame = new(this.configuration, size.Value.Width, size.Value.Height, imageFrameMetaData);
if (isTiled)
{
this.DecodeImageWithTiles(tags, frame, cancellationToken);
this.DecodeImageWithTiles(tags, frame, width, height, cancellationToken);
}
else
{
this.DecodeImageWithStrips(tags, frame, cancellationToken);
this.DecodeImageWithStrips(tags, frame, width, height, cancellationToken);
}
return frame;
@ -278,8 +289,10 @@ internal class TiffDecoderCore : ImageDecoderCore
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="tags">The IFD tags.</param>
/// <param name="frame">The image frame to decode into.</param>
/// <param name="width">The width in px units of the frame data.</param>
/// <param name="height">The height in px units of the frame data.</param>
/// <param name="cancellationToken">The token to monitor cancellation.</param>
private void DecodeImageWithStrips<TPixel>(ExifProfile tags, ImageFrame<TPixel> frame, CancellationToken cancellationToken)
private void DecodeImageWithStrips<TPixel>(ExifProfile tags, ImageFrame<TPixel> frame, int width, int height, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
int rowsPerStrip;
@ -302,6 +315,8 @@ internal class TiffDecoderCore : ImageDecoderCore
{
this.DecodeStripsPlanar(
frame,
width,
height,
rowsPerStrip,
stripOffsets,
stripByteCounts,
@ -311,6 +326,8 @@ internal class TiffDecoderCore : ImageDecoderCore
{
this.DecodeStripsChunky(
frame,
width,
height,
rowsPerStrip,
stripOffsets,
stripByteCounts,
@ -324,13 +341,13 @@ internal class TiffDecoderCore : ImageDecoderCore
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="tags">The IFD tags.</param>
/// <param name="frame">The image frame to decode into.</param>
/// <param name="width">The width in px units of the frame data.</param>
/// <param name="height">The height in px units of the frame data.</param>
/// <param name="cancellationToken">The token to monitor cancellation.</param>
private void DecodeImageWithTiles<TPixel>(ExifProfile tags, ImageFrame<TPixel> frame, CancellationToken cancellationToken)
private void DecodeImageWithTiles<TPixel>(ExifProfile tags, ImageFrame<TPixel> frame, int width, int height, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
Buffer2D<TPixel> pixels = frame.PixelBuffer;
int width = pixels.Width;
int height = pixels.Height;
if (!tags.TryGetValue(ExifTag.TileWidth, out IExifValue<Number> valueWidth))
{
@ -384,11 +401,20 @@ internal class TiffDecoderCore : ImageDecoderCore
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="frame">The image frame to decode data into.</param>
/// <param name="width">The width in px units of the frame data.</param>
/// <param name="height">The height in px units of the frame data.</param>
/// <param name="rowsPerStrip">The number of rows per strip of data.</param>
/// <param name="stripOffsets">An array of byte offsets to each strip in the image.</param>
/// <param name="stripByteCounts">An array of the size of each strip (in bytes).</param>
/// <param name="cancellationToken">The token to monitor cancellation.</param>
private void DecodeStripsPlanar<TPixel>(ImageFrame<TPixel> frame, int rowsPerStrip, Span<ulong> stripOffsets, Span<ulong> stripByteCounts, CancellationToken cancellationToken)
private void DecodeStripsPlanar<TPixel>(
ImageFrame<TPixel> frame,
int width,
int height,
int rowsPerStrip,
Span<ulong> stripOffsets,
Span<ulong> stripByteCounts,
CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
int stripsPerPixel = this.BitsPerSample.Channels;
@ -403,18 +429,18 @@ internal class TiffDecoderCore : ImageDecoderCore
{
for (int stripIndex = 0; stripIndex < stripBuffers.Length; stripIndex++)
{
int uncompressedStripSize = this.CalculateStripBufferSize(frame.Width, rowsPerStrip, stripIndex);
int uncompressedStripSize = this.CalculateStripBufferSize(width, rowsPerStrip, stripIndex);
stripBuffers[stripIndex] = this.memoryAllocator.Allocate<byte>(uncompressedStripSize);
}
using TiffBaseDecompressor decompressor = this.CreateDecompressor<TPixel>(frame.Width, bitsPerPixel);
using TiffBaseDecompressor decompressor = this.CreateDecompressor<TPixel>(width, bitsPerPixel);
TiffBasePlanarColorDecoder<TPixel> colorDecoder = this.CreatePlanarColorDecoder<TPixel>();
for (int i = 0; i < stripsPerPlane; i++)
{
cancellationToken.ThrowIfCancellationRequested();
int stripHeight = i < stripsPerPlane - 1 || frame.Height % rowsPerStrip == 0 ? rowsPerStrip : frame.Height % rowsPerStrip;
int stripHeight = i < stripsPerPlane - 1 || height % rowsPerStrip == 0 ? rowsPerStrip : height % rowsPerStrip;
int stripIndex = i;
for (int planeIndex = 0; planeIndex < stripsPerPixel; planeIndex++)
@ -430,7 +456,7 @@ internal class TiffDecoderCore : ImageDecoderCore
stripIndex += stripsPerPlane;
}
colorDecoder.Decode(stripBuffers, pixels, 0, rowsPerStrip * i, frame.Width, stripHeight);
colorDecoder.Decode(stripBuffers, pixels, 0, rowsPerStrip * i, width, stripHeight);
}
}
finally
@ -447,39 +473,48 @@ internal class TiffDecoderCore : ImageDecoderCore
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="frame">The image frame to decode data into.</param>
/// <param name="width">The width in px units of the frame data.</param>
/// <param name="height">The height in px units of the frame data.</param>
/// <param name="rowsPerStrip">The rows per strip.</param>
/// <param name="stripOffsets">The strip offsets.</param>
/// <param name="stripByteCounts">The strip byte counts.</param>
/// <param name="cancellationToken">The token to monitor cancellation.</param>
private void DecodeStripsChunky<TPixel>(ImageFrame<TPixel> frame, int rowsPerStrip, Span<ulong> stripOffsets, Span<ulong> stripByteCounts, CancellationToken cancellationToken)
private void DecodeStripsChunky<TPixel>(
ImageFrame<TPixel> frame,
int width,
int height,
int rowsPerStrip,
Span<ulong> stripOffsets,
Span<ulong> stripByteCounts,
CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
// If the rowsPerStrip has the default value, which is effectively infinity. That is, the entire image is one strip.
if (rowsPerStrip == TiffConstants.RowsPerStripInfinity)
{
rowsPerStrip = frame.Height;
rowsPerStrip = height;
}
int uncompressedStripSize = this.CalculateStripBufferSize(frame.Width, rowsPerStrip);
int uncompressedStripSize = this.CalculateStripBufferSize(width, rowsPerStrip);
int bitsPerPixel = this.BitsPerPixel;
using IMemoryOwner<byte> stripBuffer = this.memoryAllocator.Allocate<byte>(uncompressedStripSize, AllocationOptions.Clean);
Span<byte> stripBufferSpan = stripBuffer.GetSpan();
Buffer2D<TPixel> pixels = frame.PixelBuffer;
using TiffBaseDecompressor decompressor = this.CreateDecompressor<TPixel>(frame.Width, bitsPerPixel);
using TiffBaseDecompressor decompressor = this.CreateDecompressor<TPixel>(width, bitsPerPixel);
TiffBaseColorDecoder<TPixel> colorDecoder = this.CreateChunkyColorDecoder<TPixel>();
for (int stripIndex = 0; stripIndex < stripOffsets.Length; stripIndex++)
{
cancellationToken.ThrowIfCancellationRequested();
int stripHeight = stripIndex < stripOffsets.Length - 1 || frame.Height % rowsPerStrip == 0
int stripHeight = stripIndex < stripOffsets.Length - 1 || height % rowsPerStrip == 0
? rowsPerStrip
: frame.Height % rowsPerStrip;
: height % rowsPerStrip;
int top = rowsPerStrip * stripIndex;
if (top + stripHeight > frame.Height)
if (top + stripHeight > height)
{
// Make sure we ignore any strips that are not needed for the image (if too many are present).
break;
@ -493,7 +528,7 @@ internal class TiffDecoderCore : ImageDecoderCore
stripBufferSpan,
cancellationToken);
colorDecoder.Decode(stripBufferSpan, pixels, 0, top, frame.Width, stripHeight);
colorDecoder.Decode(stripBufferSpan, pixels, 0, top, width, stripHeight);
}
}

4
src/ImageSharp/Formats/Webp/WebpEncoderCore.cs

@ -160,7 +160,7 @@ internal sealed class WebpEncoderCore
// Encode additional frames
// This frame is reused to store de-duplicated pixel buffers.
using ImageFrame<TPixel> encodingFrame = new(image.Configuration, previousFrame.Size());
using ImageFrame<TPixel> encodingFrame = new(image.Configuration, previousFrame.Size);
for (int i = 1; i < image.Frames.Count; i++)
{
@ -235,7 +235,7 @@ internal sealed class WebpEncoderCore
// Encode additional frames
// This frame is reused to store de-duplicated pixel buffers.
using ImageFrame<TPixel> encodingFrame = new(image.Configuration, previousFrame.Size());
using ImageFrame<TPixel> encodingFrame = new(image.Configuration, previousFrame.Size);
for (int i = 1; i < image.Frames.Count; i++)
{

2
src/ImageSharp/Image.cs

@ -77,7 +77,7 @@ public abstract partial class Image : IDisposable, IConfigurationProvider
/// <summary>
/// Gets the size of the image in px units.
/// </summary>
public Size Size { get; internal set; }
public Size Size { get; private set; }
/// <summary>
/// Gets the bounds of the image.

20
src/ImageSharp/ImageFrame.cs

@ -25,20 +25,19 @@ public abstract partial class ImageFrame : IConfigurationProvider, IDisposable
protected ImageFrame(Configuration configuration, int width, int height, ImageFrameMetadata metadata)
{
this.Configuration = configuration;
this.Width = width;
this.Height = height;
this.Size = new(width, height);
this.Metadata = metadata;
}
/// <summary>
/// Gets the width.
/// Gets the frame width in px units.
/// </summary>
public int Width { get; private set; }
public int Width => this.Size.Width;
/// <summary>
/// Gets the height.
/// Gets the frame height in px units.
/// </summary>
public int Height { get; private set; }
public int Height => this.Size.Height;
/// <summary>
/// Gets the metadata of the frame.
@ -51,8 +50,7 @@ public abstract partial class ImageFrame : IConfigurationProvider, IDisposable
/// <summary>
/// Gets the size of the frame.
/// </summary>
/// <returns>The <see cref="Size"/></returns>
public Size Size() => new(this.Width, this.Height);
public Size Size { get; private set; }
/// <summary>
/// Gets the bounds of the frame.
@ -80,9 +78,5 @@ public abstract partial class ImageFrame : IConfigurationProvider, IDisposable
/// Updates the size of the image frame.
/// </summary>
/// <param name="size">The size.</param>
internal void UpdateSize(Size size)
{
this.Width = size.Width;
this.Height = size.Height;
}
protected void UpdateSize(Size size) => this.Size = size;
}

2
src/ImageSharp/ImageFrameCollection{TPixel}.cs

@ -414,7 +414,7 @@ public sealed class ImageFrameCollection<TPixel> : ImageFrameCollection, IEnumer
{
ImageFrame<TPixel> result = new(
this.parent.Configuration,
source.Size(),
source.Size,
source.Metadata.DeepClone());
source.CopyPixelsTo(result.PixelBuffer.FastMemoryGroup);
return result;

2
src/ImageSharp/ImageFrame{TPixel}.cs

@ -322,7 +322,7 @@ public sealed class ImageFrame<TPixel> : ImageFrame, IPixelSource<TPixel>
/// <exception cref="ArgumentException">ImageFrame{TPixel}.CopyTo(): target must be of the same size!</exception>
internal void CopyTo(Buffer2D<TPixel> target)
{
if (this.Size() != target.Size())
if (this.Size != target.Size())
{
throw new ArgumentException("ImageFrame<TPixel>.CopyTo(): target must be of the same size!", nameof(target));
}

4
src/ImageSharp/Image{TPixel}.cs

@ -419,9 +419,9 @@ public sealed class Image<TPixel> : Image
ImageFrame<TPixel>? rootFrame = frames.FirstOrDefault() ?? throw new ArgumentException("Must not be empty.", nameof(frames));
Size rootSize = rootFrame.Size();
Size rootSize = rootFrame.Size;
if (frames.Any(f => f.Size() != rootSize))
if (frames.Any(f => f.Size != rootSize))
{
throw new ArgumentException("The provided frames must be of the same size.", nameof(frames));
}

4
src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs

@ -96,7 +96,7 @@ internal class BokehBlurProcessor<TPixel> : ImageProcessor<TPixel>
}
// Create a 0-filled buffer to use to store the result of the component convolutions
using Buffer2D<Vector4> processingBuffer = this.Configuration.MemoryAllocator.Allocate2D<Vector4>(source.Size(), AllocationOptions.Clean);
using Buffer2D<Vector4> processingBuffer = this.Configuration.MemoryAllocator.Allocate2D<Vector4>(source.Size, AllocationOptions.Clean);
// Perform the 1D convolutions on all the kernel components and accumulate the results
this.OnFrameApplyCore(source, sourceRectangle, this.Configuration, processingBuffer);
@ -134,7 +134,7 @@ internal class BokehBlurProcessor<TPixel> : ImageProcessor<TPixel>
Buffer2D<Vector4> processingBuffer)
{
// Allocate the buffer with the intermediate convolution results
using Buffer2D<ComplexVector4> firstPassBuffer = configuration.MemoryAllocator.Allocate2D<ComplexVector4>(source.Size());
using Buffer2D<ComplexVector4> firstPassBuffer = configuration.MemoryAllocator.Allocate2D<ComplexVector4>(source.Size);
// Unlike in the standard 2 pass convolution processor, we use a rectangle of 1x the interest width
// to speedup the actual convolution, by applying bulk pixel conversion and clamping calculation.

2
src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs

@ -66,7 +66,7 @@ internal class Convolution2PassProcessor<TPixel> : ImageProcessor<TPixel>
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source)
{
using Buffer2D<TPixel> firstPassPixels = this.Configuration.MemoryAllocator.Allocate2D<TPixel>(source.Size());
using Buffer2D<TPixel> firstPassPixels = this.Configuration.MemoryAllocator.Allocate2D<TPixel>(source.Size);
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());

2
src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs

@ -51,7 +51,7 @@ internal class ConvolutionProcessor<TPixel> : ImageProcessor<TPixel>
protected override void OnFrameApply(ImageFrame<TPixel> source)
{
MemoryAllocator allocator = this.Configuration.MemoryAllocator;
using Buffer2D<TPixel> targetPixels = allocator.Allocate2D<TPixel>(source.Size());
using Buffer2D<TPixel> targetPixels = allocator.Allocate2D<TPixel>(source.Size);
source.CopyTo(targetPixels);

2
src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs

@ -38,7 +38,7 @@ internal class OilPaintingProcessor<TPixel> : ImageProcessor<TPixel>
int levels = Math.Clamp(this.definition.Levels, 1, 255);
int brushSize = Math.Clamp(this.definition.BrushSize, 1, Math.Min(source.Width, source.Height));
using Buffer2D<TPixel> targetPixels = this.Configuration.MemoryAllocator.Allocate2D<TPixel>(source.Size());
using Buffer2D<TPixel> targetPixels = this.Configuration.MemoryAllocator.Allocate2D<TPixel>(source.Size);
source.CopyTo(targetPixels);

11
tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs

@ -23,7 +23,6 @@ public class TiffDecoderTests : TiffDecoderBaseTester
public static readonly string[] MultiframeTestImages = Multiframes;
[Theory]
[WithFile(MultiframeDifferentSize, PixelTypes.Rgba32)]
[WithFile(MultiframeDifferentVariants, PixelTypes.Rgba32)]
[WithFile(Cmyk64BitDeflate, PixelTypes.Rgba32)]
public void ThrowsNotSupported<TPixel>(TestImageProvider<TPixel> provider)
@ -596,6 +595,16 @@ public class TiffDecoderTests : TiffDecoderBaseTester
Assert.Equal(1, image.Frames.Count);
}
[Theory]
[WithFile(MultiFrameMipMap, PixelTypes.Rgba32)]
public void CanDecode_MultiFrameMipMap<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage(TiffDecoder.Instance);
Assert.Equal(7, image.Frames.Count);
image.DebugSaveMultiFrame(provider);
}
[Theory]
[WithFile(RgbJpegCompressed, PixelTypes.Rgba32)]
[WithFile(RgbJpegCompressed2, PixelTypes.Rgba32)]

1
tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderMultiframeTests.cs

@ -18,7 +18,6 @@ public class TiffEncoderMultiframeTests : TiffEncoderBaseTester
where TPixel : unmanaged, IPixel<TPixel> => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb);
[Theory]
[WithFile(MultiframeDifferentSize, PixelTypes.Rgba32)]
[WithFile(MultiframeDifferentVariants, PixelTypes.Rgba32)]
public void TiffEncoder_EncodeMultiframe_NotSupport<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => Assert.Throws<NotSupportedException>(() => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb));

3
tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -16,7 +15,7 @@ public class ExactImageComparer : ImageComparer
ImageFrame<TPixelA> expected,
ImageFrame<TPixelB> actual)
{
if (expected.Size() != actual.Size())
if (expected.Size != actual.Size)
{
throw new InvalidOperationException("Calling ImageComparer is invalid when dimensions mismatch!");
}

3
tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs

@ -2,7 +2,6 @@
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -58,7 +57,7 @@ public class TolerantImageComparer : ImageComparer
public override ImageSimilarityReport<TPixelA, TPixelB> CompareImagesOrFrames<TPixelA, TPixelB>(int index, ImageFrame<TPixelA> expected, ImageFrame<TPixelB> actual)
{
if (expected.Size() != actual.Size())
if (expected.Size != actual.Size)
{
throw new InvalidOperationException("Calling ImageComparer is invalid when dimensions mismatch!");
}

Loading…
Cancel
Save