Browse Source

Initialize pixel type info from decoder.

pull/2751/head
James Jackson-South 2 years ago
parent
commit
a06511f6d2
  1. 2
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  2. 1
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  3. 1
      src/ImageSharp/Formats/ImageDecoder.cs
  4. 2
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  5. 10
      src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs
  6. 18
      src/ImageSharp/Formats/Pbm/PbmMetadata.cs
  7. 25
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  8. 12
      src/ImageSharp/Formats/Png/PngMetadata.cs
  9. 2
      src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs
  10. 1
      src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
  11. 2
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
  12. 1
      src/ImageSharp/Formats/Webp/WebpDecoderCore.cs
  13. 25
      src/ImageSharp/ImageInfo.cs
  14. 16
      src/ImageSharp/Metadata/ImageMetadata.cs
  15. 21
      tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
  16. 18
      tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs
  17. 2
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
  18. 6
      tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
  19. 4
      tests/ImageSharp.Tests/Formats/Qoi/QoiEncoderTests.cs
  20. 18
      tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs
  21. 2
      tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderBaseTester.cs
  22. 3
      tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderBaseTester.cs
  23. 2
      tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs
  24. 9
      tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs
  25. 2
      tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs
  26. 3
      tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs
  27. 25
      tests/ImageSharp.Tests/ImageInfoTests.cs
  28. 14
      tests/ImageSharp.Tests/TestFormat.cs
  29. 43
      tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs
  30. 94
      tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/ReferenceCodecUtilities.cs
  31. 26
      tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs
  32. 1
      tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs
  33. 4
      tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs
  34. 15
      tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs
  35. 8
      tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs
  36. 2
      tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs
  37. 26
      tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs

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

@ -208,7 +208,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
public ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken)
{
this.ReadImageHeaders(stream, out _, out _);
return new ImageInfo(new PixelTypeInfo(this.infoHeader.BitsPerPixel), new(this.infoHeader.Width, this.infoHeader.Height), this.metadata);
return new ImageInfo(new(this.infoHeader.Width, this.infoHeader.Height), this.metadata);
}
/// <summary>

1
src/ImageSharp/Formats/Gif/GifDecoderCore.cs

@ -249,7 +249,6 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
}
return new ImageInfo(
new PixelTypeInfo(this.logicalScreenDescriptor.BitsPerPixel),
new(this.logicalScreenDescriptor.Width, this.logicalScreenDescriptor.Height),
this.metadata,
framesMetadata);

1
src/ImageSharp/Formats/ImageDecoder.cs

@ -307,6 +307,7 @@ public abstract class ImageDecoder : IImageDecoder
if (configuration.ImageFormatsManager.TryFindFormatByDecoder(this, out IImageFormat? format))
{
info.Metadata.DecodedImageFormat = format;
info.PixelType = info.Metadata.GetDecodedPixelTypeInfo();
foreach (ImageFrameMetadata frame in info.FrameMetadataCollection)
{

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

@ -226,7 +226,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
this.InitDerivedMetadataProperties();
Size pixelSize = this.Frame.PixelSize;
return new ImageInfo(new PixelTypeInfo(this.Frame.BitsPerPixel), new(pixelSize.Width, pixelSize.Height), this.Metadata);
return new ImageInfo(new(pixelSize.Width, pixelSize.Height), this.Metadata);
}
/// <summary>

10
src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs

@ -69,7 +69,7 @@ internal sealed class PbmDecoderCore : IImageDecoderInternals
{
this.ProcessHeader(stream);
var image = new Image<TPixel>(this.configuration, this.pixelSize.Width, this.pixelSize.Height, this.metadata);
Image<TPixel> image = new(this.configuration, this.pixelSize.Width, this.pixelSize.Height, this.metadata);
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
@ -86,10 +86,9 @@ internal sealed class PbmDecoderCore : IImageDecoderInternals
public ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken)
{
this.ProcessHeader(stream);
// BlackAndWhite pixels are encoded into a byte.
int bitsPerPixel = this.componentType == PbmComponentType.Short ? 16 : 8;
return new ImageInfo(new PixelTypeInfo(bitsPerPixel), new(this.pixelSize.Width, this.pixelSize.Height), this.metadata);
return new ImageInfo(
new(this.pixelSize.Width, this.pixelSize.Height),
this.metadata);
}
/// <summary>
@ -97,6 +96,7 @@ internal sealed class PbmDecoderCore : IImageDecoderInternals
/// </summary>
/// <param name="stream">The input stream.</param>
/// <exception cref="InvalidImageContentException">An EOF marker has been read before the image has been decoded.</exception>
[MemberNotNull(nameof(metadata))]
private void ProcessHeader(BufferedReadStream stream)
{
Span<byte> buffer = stackalloc byte[2];

18
src/ImageSharp/Formats/Pbm/PbmMetadata.cs

@ -97,20 +97,20 @@ public class PbmMetadata : IFormatMetadata<PbmMetadata>
colorType = PixelColorType.Binary;
info = PixelComponentInfo.Create(1, bpp, 1);
break;
case PbmColorType.Grayscale:
bpp = 8;
colorType = PixelColorType.Luminance;
info = PixelComponentInfo.Create(1, bpp, 8);
break;
case PbmColorType.Rgb:
bpp = 24;
bpp = this.ComponentType == PbmComponentType.Short ? 48 : 24;
colorType = PixelColorType.RGB;
info = PixelComponentInfo.Create(3, bpp, 8, 8, 8);
info = this.ComponentType == PbmComponentType.Short
? PixelComponentInfo.Create(3, bpp, 16, 16, 16)
: PixelComponentInfo.Create(3, bpp, 8, 8, 8);
break;
case PbmColorType.Grayscale:
default:
bpp = 8;
bpp = this.ComponentType == PbmComponentType.Short ? 16 : 8;
colorType = PixelColorType.Luminance;
info = PixelComponentInfo.Create(1, bpp, 8);
info = this.ComponentType == PbmComponentType.Short
? PixelComponentInfo.Create(1, bpp, bpp)
: PixelComponentInfo.Create(1, bpp, bpp);
break;
}

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

@ -515,7 +515,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
// Both PLTE and tRNS chunks, if present, have been read at this point as per spec.
AssignColorPalette(this.palette, this.paletteAlpha, pngMetadata);
return new ImageInfo(new PixelTypeInfo(this.CalculateBitsPerPixel()), new(this.header.Width, this.header.Height), metadata);
return new ImageInfo(new(this.header.Width, this.header.Height), metadata);
}
finally
{
@ -680,29 +680,6 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
this.scanline = this.configuration.MemoryAllocator.Allocate<byte>(this.bytesPerScanline, AllocationOptions.Clean);
}
/// <summary>
/// Calculates the correct number of bits per pixel for the given color type.
/// </summary>
/// <returns>The <see cref="int"/></returns>
private int CalculateBitsPerPixel()
{
switch (this.pngColorType)
{
case PngColorType.Grayscale:
case PngColorType.Palette:
return this.header.BitDepth;
case PngColorType.GrayscaleWithAlpha:
return this.header.BitDepth * 2;
case PngColorType.Rgb:
return this.header.BitDepth * 3;
case PngColorType.RgbWithAlpha:
return this.header.BitDepth * 4;
default:
PngThrowHelper.ThrowNotSupportedColor();
return -1;
}
}
/// <summary>
/// Calculates the correct number of bytes per pixel for the given color type.
/// </summary>

12
src/ImageSharp/Formats/Png/PngMetadata.cs

@ -176,9 +176,9 @@ public class PngMetadata : IFormatMetadata<PngMetadata>
break;
case PngColorType.Grayscale:
bpp = 8;
bpp = (int)this.BitDepth;
colorType = PixelColorType.Luminance;
info = PixelComponentInfo.Create(1, bpp, 8);
info = PixelComponentInfo.Create(1, bpp, bpp);
break;
case PngColorType.GrayscaleWithAlpha:
@ -200,15 +200,15 @@ public class PngMetadata : IFormatMetadata<PngMetadata>
case PngColorType.Rgb:
if (this.BitDepth == PngBitDepth.Bit16)
{
bpp = 24;
bpp = 48;
colorType = PixelColorType.RGB;
info = PixelComponentInfo.Create(3, bpp, 8, 8, 8);
info = PixelComponentInfo.Create(3, bpp, 16, 16, 16);
break;
}
bpp = 48;
bpp = 24;
colorType = PixelColorType.RGB;
info = PixelComponentInfo.Create(3, bpp, 16, 16, 16);
info = PixelComponentInfo.Create(3, bpp, 8, 8, 8);
break;
case PngColorType.RgbWithAlpha:

2
src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs

@ -73,7 +73,7 @@ internal class QoiDecoderCore : IImageDecoderInternals
qoiMetadata.Channels = this.header.Channels;
qoiMetadata.ColorSpace = this.header.ColorSpace;
return new ImageInfo(pixelType, size, metadata);
return new ImageInfo(size, metadata);
}
/// <summary>

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

@ -646,7 +646,6 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
{
this.ReadFileHeader(stream);
return new ImageInfo(
new PixelTypeInfo(this.fileHeader.PixelDepth),
new(this.fileHeader.Width, this.fileHeader.Height),
this.metadata);
}

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

@ -234,7 +234,7 @@ internal class TiffDecoderCore : IImageDecoderInternals
int width = GetImageWidth(rootFrameExifProfile);
int height = GetImageHeight(rootFrameExifProfile);
return new ImageInfo(new PixelTypeInfo((int)framesMetadata[0].GetTiffMetadata().BitsPerPixel), new(width, height), metadata, framesMetadata);
return new ImageInfo(new(width, height), metadata, framesMetadata);
}
/// <summary>

1
src/ImageSharp/Formats/Webp/WebpDecoderCore.cs

@ -144,7 +144,6 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable
using (this.webImageInfo = this.ReadVp8Info(stream, metadata, true))
{
return new ImageInfo(
new PixelTypeInfo((int)this.webImageInfo.BitsPerPixel),
new Size((int)this.webImageInfo.Width, (int)this.webImageInfo.Height),
metadata);
}

25
src/ImageSharp/ImageInfo.cs

@ -14,40 +14,43 @@ public class ImageInfo
/// <summary>
/// Initializes a new instance of the <see cref="ImageInfo"/> class.
/// </summary>
/// <param name="pixelType">The pixel type information.</param>
/// <param name="size">The size of the image in px units.</param>
/// <param name="metadata">The image metadata.</param>
public ImageInfo(
PixelTypeInfo pixelType,
Size size,
ImageMetadata? metadata)
: this(pixelType, size, metadata, null)
ImageMetadata metadata)
: this(size, metadata, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ImageInfo"/> class.
/// </summary>
/// <param name="pixelType">The pixel type information.</param>
/// <param name="size">The size of the image in px units.</param>
/// <param name="metadata">The image metadata.</param>
/// <param name="frameMetadataCollection">The collection of image frame metadata.</param>
public ImageInfo(
PixelTypeInfo pixelType,
Size size,
ImageMetadata? metadata,
ImageMetadata metadata,
IReadOnlyList<ImageFrameMetadata>? frameMetadataCollection)
{
this.PixelType = pixelType;
this.Size = size;
this.Metadata = metadata ?? new ImageMetadata();
this.FrameMetadataCollection = frameMetadataCollection ?? Array.Empty<ImageFrameMetadata>();
this.Metadata = metadata;
// PixelTpe is normally set following decoding
// See ImageDecoder.SetDecoderFormat(Configuration configuration, ImageInfo info).
if (metadata.DecodedImageFormat is not null)
{
this.PixelType = metadata.GetDecodedPixelTypeInfo();
}
this.FrameMetadataCollection = frameMetadataCollection ?? [];
}
/// <summary>
/// Gets information about the image pixels.
/// </summary>
public PixelTypeInfo PixelType { get; }
public PixelTypeInfo PixelType { get; internal set; }
/// <summary>
/// Gets the image width in px units.

16
src/ImageSharp/Metadata/ImageMetadata.cs

@ -7,6 +7,7 @@ using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
using SixLabors.ImageSharp.Metadata.Profiles.Iptc;
using SixLabors.ImageSharp.Metadata.Profiles.Xmp;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Metadata;
@ -212,12 +213,25 @@ public sealed class ImageMetadata : IDeepCloneable<ImageMetadata>
/// The <typeparamref name="TFormatMetadata"/>.
/// </returns>
public TFormatMetadata CloneFormatMetadata<TFormatMetadata>(IImageFormat<TFormatMetadata> key)
where TFormatMetadata : class, IFormatMetadata<TFormatMetadata>, new()
where TFormatMetadata : class, IFormatMetadata<TFormatMetadata>
=> ((IDeepCloneable<TFormatMetadata>)this.GetFormatMetadata(key)).DeepClone();
/// <inheritdoc/>
public ImageMetadata DeepClone() => new(this);
internal PixelTypeInfo GetDecodedPixelTypeInfo()
{
// None found. Check if we have a decoded format to convert from.
if (this.DecodedImageFormat is not null
&& this.formatMetadata.TryGetValue(this.DecodedImageFormat, out IFormatMetadata? decodedMetadata))
{
return decodedMetadata.GetPixelTypeInfo();
}
// This should never happen.
return default;
}
/// TODO: This should be called on save.
/// <summary>
/// Synchronizes the profiles with the current metadata.

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

@ -4,6 +4,7 @@
using Microsoft.DotNet.RemoteExecutor;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
@ -112,7 +113,7 @@ public class BmpDecoderTests
{
using Image<TPixel> image = provider.GetImage(BmpDecoder.Instance);
image.DebugSave(provider);
image.CompareToOriginal(provider, new SystemDrawingReferenceDecoder());
image.CompareToOriginal(provider, new SystemDrawingReferenceDecoder(BmpFormat.Instance));
}
[Theory]
@ -219,7 +220,7 @@ public class BmpDecoderTests
image.DebugSave(provider);
if (TestEnvironment.IsWindows)
{
image.CompareToOriginal(provider, new SystemDrawingReferenceDecoder());
image.CompareToOriginal(provider, new SystemDrawingReferenceDecoder(BmpFormat.Instance));
}
}
@ -232,7 +233,7 @@ public class BmpDecoderTests
BmpDecoderOptions options = new() { RleSkippedPixelHandling = RleSkippedPixelHandling.FirstColorOfPalette };
using Image<TPixel> image = provider.GetImage(BmpDecoder.Instance, options);
image.DebugSave(provider);
image.CompareToOriginal(provider, new MagickReferenceDecoder());
image.CompareToOriginal(provider, MagickReferenceDecoder.Png);
}
[Theory]
@ -251,7 +252,7 @@ public class BmpDecoderTests
BmpDecoderOptions options = new() { RleSkippedPixelHandling = RleSkippedPixelHandling.FirstColorOfPalette };
using Image<TPixel> image = provider.GetImage(BmpDecoder.Instance, options);
image.DebugSave(provider);
image.CompareToOriginal(provider, new MagickReferenceDecoder());
image.CompareToOriginal(provider, MagickReferenceDecoder.Png);
}
[Theory]
@ -298,7 +299,7 @@ public class BmpDecoderTests
{
using Image<TPixel> image = provider.GetImage(BmpDecoder.Instance);
image.DebugSave(provider);
image.CompareToOriginal(provider, new MagickReferenceDecoder());
image.CompareToOriginal(provider, MagickReferenceDecoder.Png);
}
[Theory]
@ -314,7 +315,7 @@ public class BmpDecoderTests
// which should be remapped to 255 for RGBA32, but the magick decoder has a value of 191 set.
// The total difference without the alpha channel is still: 0.0204%
// Exporting the image as PNG with GIMP yields to the same result as the ImageSharp implementation.
image.CompareToOriginal(provider, ImageComparer.TolerantPercentage(6.1f), new MagickReferenceDecoder());
image.CompareToOriginal(provider, ImageComparer.TolerantPercentage(6.1f), MagickReferenceDecoder.Png);
}
[Theory]
@ -327,7 +328,7 @@ public class BmpDecoderTests
image.DebugSave(provider);
// Do not validate. Reference files will fail validation.
image.CompareToOriginal(provider, new MagickReferenceDecoder(false));
image.CompareToOriginal(provider, new MagickReferenceDecoder(PngFormat.Instance, false));
}
[Theory]
@ -347,7 +348,7 @@ public class BmpDecoderTests
{
using Image<TPixel> image = provider.GetImage(BmpDecoder.Instance);
image.DebugSave(provider);
image.CompareToOriginal(provider, new MagickReferenceDecoder());
image.CompareToOriginal(provider, MagickReferenceDecoder.Png);
}
[Theory]
@ -394,7 +395,7 @@ public class BmpDecoderTests
{
using Image<TPixel> image = provider.GetImage(BmpDecoder.Instance);
image.DebugSave(provider);
image.CompareToOriginal(provider, new MagickReferenceDecoder());
image.CompareToOriginal(provider, MagickReferenceDecoder.Png);
}
[Theory]
@ -404,7 +405,7 @@ public class BmpDecoderTests
{
using Image<TPixel> image = provider.GetImage(BmpDecoder.Instance);
image.DebugSave(provider);
image.CompareToOriginal(provider, new MagickReferenceDecoder());
image.CompareToOriginal(provider, MagickReferenceDecoder.Png);
}
[Theory]

18
tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs

@ -20,11 +20,11 @@ public class BmpEncoderTests
private static BmpEncoder BmpEncoder => new();
public static readonly TheoryData<BmpBitsPerPixel> BitsPerPixel =
new()
{
BmpBitsPerPixel.Bit24,
BmpBitsPerPixel.Bit32
};
new()
{
BmpBitsPerPixel.Bit24,
BmpBitsPerPixel.Bit32
};
public static readonly TheoryData<string, int, int, PixelResolutionUnit> RatioFiles =
new()
@ -287,7 +287,7 @@ public class BmpEncoderTests
provider,
extension: "bmp",
appendPixelTypeToFileName: false,
decoder: new MagickReferenceDecoder(false));
decoder: new MagickReferenceDecoder(BmpFormat.Instance, false));
}
[Theory]
@ -318,7 +318,7 @@ public class BmpEncoderTests
provider,
extension: "bmp",
appendPixelTypeToFileName: false,
decoder: new MagickReferenceDecoder(false));
decoder: new MagickReferenceDecoder(BmpFormat.Instance, false));
}
[Theory]
@ -380,8 +380,8 @@ public class BmpEncoderTests
{
using Image<TPixel> image = provider.GetImage();
using var reencodedStream = new MemoryStream();
var encoder = new BmpEncoder
using MemoryStream reencodedStream = new();
BmpEncoder encoder = new()
{
BitsPerPixel = bitsPerPixel,
SupportTransparency = false,

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

@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg;
[ValidateDisposedMemoryAllocations]
public partial class JpegDecoderTests
{
private static MagickReferenceDecoder ReferenceDecoder => new();
private static MagickReferenceDecoder ReferenceDecoder => MagickReferenceDecoder.Jpeg;
public const PixelTypes CommonNonDefaultPixelTypes = PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.Bgr24 | PixelTypes.RgbaVector;

6
tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs

@ -485,7 +485,7 @@ public partial class PngDecoderTests
if (compare)
{
// Magick cannot actually decode this image to compare.
image.CompareToOriginal(provider, new MagickReferenceDecoder(false));
image.CompareToOriginal(provider, new MagickReferenceDecoder(PngFormat.Instance, false));
}
}
@ -552,7 +552,7 @@ public partial class PngDecoderTests
// We don't have another x-plat reference decoder that can be compared for this image.
if (TestEnvironment.IsWindows)
{
image.CompareToOriginal(provider, ImageComparer.Exact, SystemDrawingReferenceDecoder.Instance);
image.CompareToOriginal(provider, ImageComparer.Exact, SystemDrawingReferenceDecoder.Png);
}
});
Assert.Null(ex);
@ -614,7 +614,7 @@ public partial class PngDecoderTests
// We don't have another x-plat reference decoder that can be compared for this image.
if (TestEnvironment.IsWindows)
{
image.CompareToOriginal(provider, ImageComparer.Exact, SystemDrawingReferenceDecoder.Instance);
image.CompareToOriginal(provider, ImageComparer.Exact, SystemDrawingReferenceDecoder.Png);
}
});
Assert.NotNull(ex);

4
tests/ImageSharp.Tests/Formats/Qoi/QoiEncoderTests.cs

@ -24,7 +24,7 @@ public class QoiEncoderTests
public static void Encode<TPixel>(TestImageProvider<TPixel> provider, QoiChannels channels, QoiColorSpace colorSpace)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage(new MagickReferenceDecoder());
using Image<TPixel> image = provider.GetImage(new MagickReferenceDecoder(QoiFormat.Instance));
using MemoryStream stream = new();
QoiEncoder encoder = new()
{
@ -34,7 +34,7 @@ public class QoiEncoderTests
image.Save(stream, encoder);
stream.Position = 0;
using Image<TPixel> encodedImage = (Image<TPixel>)Image.Load(stream);
using Image<TPixel> encodedImage = Image.Load<TPixel>(stream);
QoiMetadata qoiMetadata = encodedImage.Metadata.GetQoiMetadata();
ImageComparer.Exact.CompareImages(image, encodedImage);

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

@ -121,16 +121,14 @@ public class TgaEncoderTests
where TPixel : unmanaged, IPixel<TPixel>
{
// The test image has alternating black and white pixels, which should make using always RLE data inefficient.
using (Image<TPixel> image = provider.GetImage())
{
var options = new TgaEncoder() { Compression = TgaCompression.RunLength };
using (var memStream = new MemoryStream())
{
image.Save(memStream, options);
byte[] imageBytes = memStream.ToArray();
Assert.Equal(expectedBytes, imageBytes.Length);
}
}
using Image<TPixel> image = provider.GetImage();
TgaEncoder options = new() { BitsPerPixel = TgaBitsPerPixel.Bit24, Compression = TgaCompression.RunLength };
using MemoryStream memStream = new();
image.Save(memStream, options);
byte[] imageBytes = memStream.ToArray();
Assert.Equal(expectedBytes, imageBytes.Length);
}
// Run length encoded pixels should not exceed row boundaries.

2
tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderBaseTester.cs

@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff;
public abstract class TiffDecoderBaseTester
{
protected static MagickReferenceDecoder ReferenceDecoder => new();
protected static MagickReferenceDecoder ReferenceDecoder => new(TiffFormat.Instance);
protected static void TestTiffDecoder<TPixel>(TestImageProvider<TPixel> provider, IImageDecoder referenceDecoder = null, bool useExactComparer = true, float compareTolerance = 0.001f)
where TPixel : unmanaged, IPixel<TPixel>

3
tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderBaseTester.cs

@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff;
[Trait("Format", "Tiff")]
public abstract class TiffEncoderBaseTester
{
protected static readonly IImageDecoder ReferenceDecoder = new MagickReferenceDecoder();
protected static readonly IImageDecoder ReferenceDecoder = new MagickReferenceDecoder(TiffFormat.Instance);
protected static void TestStripLength<TPixel>(
TestImageProvider<TPixel> provider,
@ -48,7 +48,6 @@ public abstract class TiffEncoderBaseTester
Number[] stripByteCounts = exifProfileOutput.GetValue(ExifTag.StripByteCounts)?.Value;
Assert.NotNull(stripByteCounts);
Assert.True(stripByteCounts.Length > 1);
Assert.NotNull(outputMeta.BitsPerPixel);
foreach (Number sz in stripByteCounts)
{

2
tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs

@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp;
[ValidateDisposedMemoryAllocations]
public class WebpDecoderTests
{
private static MagickReferenceDecoder ReferenceDecoder => new();
private static MagickReferenceDecoder ReferenceDecoder => MagickReferenceDecoder.WebP;
private static string TestImageLossyHorizontalFilterPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, Lossy.AlphaCompressedHorizontalFilter);

9
tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs

@ -169,10 +169,11 @@ public class WebpEncoderTests
}
[Theory]
[WithFile(Flag, PixelTypes.Rgba32, WebpFileFormatType.Lossy)] // If its not a webp input image, it should default to lossy.
[WithFile(TestImages.Jpeg.Baseline.Jpeg410, PixelTypes.Rgba32, WebpFileFormatType.Lossy)] // Input is lossy jpeg.
[WithFile(Flag, PixelTypes.Rgba32, WebpFileFormatType.Lossless)] // Input is lossless png.
[WithFile(Lossless.NoTransform1, PixelTypes.Rgba32, WebpFileFormatType.Lossless)]
[WithFile(Lossy.BikeWithExif, PixelTypes.Rgba32, WebpFileFormatType.Lossy)]
public void Encode_PreserveRatio<TPixel>(TestImageProvider<TPixel> provider, WebpFileFormatType expectedFormat)
public void Encode_PreserveEncodingType<TPixel>(TestImageProvider<TPixel> provider, WebpFileFormatType expectedFormat)
where TPixel : unmanaged, IPixel<TPixel>
{
WebpEncoder options = new();
@ -440,7 +441,7 @@ public class WebpEncoderTests
"with_alpha",
encoder,
ImageComparer.Tolerant(0.04f),
referenceDecoder: new MagickReferenceDecoder());
referenceDecoder: MagickReferenceDecoder.WebP);
int encodedBytes = File.ReadAllBytes(encodedFile).Length;
Assert.True(encodedBytes <= expectedFileSize, $"encoded bytes are {encodedBytes} and should be smaller then expected file size of {expectedFileSize}");
@ -468,7 +469,7 @@ public class WebpEncoderTests
"with_alpha_compressed",
encoder,
ImageComparer.Tolerant(0.04f),
referenceDecoder: new MagickReferenceDecoder());
referenceDecoder: MagickReferenceDecoder.WebP);
int encodedBytes = File.ReadAllBytes(encodedFile).Length;
Assert.True(encodedBytes <= expectedFileSize, $"encoded bytes are {encodedBytes} and should be smaller then expected file size of {expectedFileSize}");

2
tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs

@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp;
[Trait("Format", "Webp")]
public class YuvConversionTests
{
private static MagickReferenceDecoder ReferenceDecoder => new();
private static MagickReferenceDecoder ReferenceDecoder => MagickReferenceDecoder.WebP;
private static string TestImageLossyFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Webp.Lossy.NoFilter06);

3
tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs

@ -4,6 +4,7 @@
using Moq;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
@ -57,7 +58,7 @@ public partial class ImageTests
// TODO: Remove all this mocking. It's too complicated and we can now use fakes.
this.localStreamReturnImageRgba32 = new Image<Rgba32>(1, 1);
this.localStreamReturnImageAgnostic = new Image<Bgra4444>(1, 1);
this.LocalImageInfo = new(new PixelTypeInfo(8), new(1, 1), new ImageMetadata());
this.LocalImageInfo = new(new(1, 1), new ImageMetadata() { DecodedImageFormat = PngFormat.Instance });
this.localImageFormatMock = new Mock<IImageFormat>();

25
tests/ImageSharp.Tests/ImageInfoTests.cs

@ -1,8 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Tests;
@ -15,12 +15,14 @@ public class ImageInfoTests
const int height = 60;
Size size = new(width, height);
Rectangle rectangle = new(0, 0, width, height);
PixelTypeInfo pixelType = new(8);
ImageMetadata meta = new();
ImageInfo info = new(pixelType, size, meta);
// Initialize the metadata to match standard decoding behavior.
ImageMetadata meta = new() { DecodedImageFormat = PngFormat.Instance };
meta.GetPngMetadata();
Assert.Equal(pixelType, info.PixelType);
ImageInfo info = new(size, meta);
Assert.NotEqual(default, info.PixelType);
Assert.Equal(width, info.Width);
Assert.Equal(height, info.Height);
Assert.Equal(size, info.Size);
@ -35,13 +37,16 @@ public class ImageInfoTests
const int height = 60;
Size size = new(width, height);
Rectangle rectangle = new(0, 0, width, height);
PixelTypeInfo pixelType = new(8);
ImageMetadata meta = new();
IReadOnlyList<ImageFrameMetadata> frameMetadata = new List<ImageFrameMetadata>() { new() };
ImageInfo info = new(pixelType, size, meta, frameMetadata);
// Initialize the metadata to match standard decoding behavior.
ImageMetadata meta = new() { DecodedImageFormat = PngFormat.Instance };
meta.GetPngMetadata();
IReadOnlyList<ImageFrameMetadata> frameMetadata = [new()];
ImageInfo info = new(size, meta, frameMetadata);
Assert.Equal(pixelType, info.PixelType);
Assert.NotEqual(default, info.PixelType);
Assert.Equal(width, info.Width);
Assert.Equal(height, info.Height);
Assert.Equal(size, info.Size);

14
tests/ImageSharp.Tests/TestFormat.cs

@ -7,6 +7,7 @@ using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.TestUtilities;
using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
namespace SixLabors.ImageSharp.Tests;
@ -89,7 +90,7 @@ public class TestFormat : IImageFormatConfigurationModule, IImageFormat
{
if (!this.sampleImages.ContainsKey(typeof(TPixel)))
{
this.sampleImages.Add(typeof(TPixel), new Image<TPixel>(1, 1));
this.sampleImages.Add(typeof(TPixel), ReferenceCodecUtilities.EnsureDecodedMetadata(new Image<TPixel>(1, 1), this));
}
return (Image<TPixel>)this.sampleImages[typeof(TPixel)];
@ -202,11 +203,12 @@ public class TestFormat : IImageFormatConfigurationModule, IImageFormat
protected override ImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
Image<TestPixelForAgnosticDecode> image =
this.Decode<TestPixelForAgnosticDecode>(this.CreateDefaultSpecializedOptions(options), stream, cancellationToken);
ImageFrameCollection<TestPixelForAgnosticDecode> m = image.Frames;
return new(image.PixelType, image.Size, image.Metadata, new List<ImageFrameMetadata>(image.Frames.Select(x => x.Metadata)));
using Image<TestPixelForAgnosticDecode> image = this.Decode<TestPixelForAgnosticDecode>(this.CreateDefaultSpecializedOptions(options), stream, cancellationToken);
ImageMetadata metadata = image.Metadata;
return new(image.Size, metadata, new List<ImageFrameMetadata>(image.Frames.Select(x => x.Metadata)))
{
PixelType = metadata.GetDecodedPixelTypeInfo()
};
}
protected override TestDecoderOptions CreateDefaultSpecializedOptions(DecoderOptions options)

43
tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs

@ -5,6 +5,11 @@ using System.Runtime.InteropServices;
using ImageMagick;
using ImageMagick.Formats;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Formats.Webp;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
@ -13,19 +18,34 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
public class MagickReferenceDecoder : ImageDecoder
{
private readonly IImageFormat imageFormat;
private readonly bool validate;
public MagickReferenceDecoder()
: this(true)
public MagickReferenceDecoder(IImageFormat imageFormat)
: this(imageFormat, true)
{
}
public MagickReferenceDecoder(bool validate) => this.validate = validate;
public MagickReferenceDecoder(IImageFormat imageFormat, bool validate)
{
this.imageFormat = imageFormat;
this.validate = validate;
}
public static MagickReferenceDecoder Png { get; } = new MagickReferenceDecoder(PngFormat.Instance);
public static MagickReferenceDecoder Bmp { get; } = new MagickReferenceDecoder(BmpFormat.Instance);
public static MagickReferenceDecoder Jpeg { get; } = new MagickReferenceDecoder(JpegFormat.Instance);
public static MagickReferenceDecoder Instance { get; } = new();
public static MagickReferenceDecoder Tiff { get; } = new MagickReferenceDecoder(TiffFormat.Instance);
public static MagickReferenceDecoder WebP { get; } = new MagickReferenceDecoder(WebpFormat.Instance);
protected override Image<TPixel> Decode<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
ImageMetadata metadata = new();
Configuration configuration = options.Configuration;
BmpReadDefines bmpReadDefines = new()
{
@ -44,7 +64,7 @@ public class MagickReferenceDecoder : ImageDecoder
settings.SetDefines(pngReadDefines);
using MagickImageCollection magickImageCollection = new(stream, settings);
List<ImageFrame<TPixel>> framesList = new();
List<ImageFrame<TPixel>> framesList = [];
foreach (IMagickImage<ushort> magicFrame in magickImageCollection)
{
ImageFrame<TPixel> frame = new(configuration, magicFrame.Width, magicFrame.Height);
@ -61,6 +81,11 @@ public class MagickReferenceDecoder : ImageDecoder
}
else if (magicFrame.Depth is 16 or 14)
{
if (this.imageFormat is PngFormat png)
{
metadata.GetPngMetadata().BitDepth = PngBitDepth.Bit16;
}
ushort[] data = pixels.ToShortArray(PixelMapping.RGBA);
Span<byte> bytes = MemoryMarshal.Cast<ushort, byte>(data.AsSpan());
FromRgba64Bytes(configuration, bytes, framePixels);
@ -71,7 +96,7 @@ public class MagickReferenceDecoder : ImageDecoder
}
}
return new Image<TPixel>(configuration, new ImageMetadata(), framesList);
return ReferenceCodecUtilities.EnsureDecodedMetadata<TPixel>(new(configuration, metadata, framesList), this.imageFormat);
}
protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
@ -80,7 +105,11 @@ public class MagickReferenceDecoder : ImageDecoder
protected override ImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
using Image<Rgba32> image = this.Decode<Rgba32>(options, stream, cancellationToken);
return new(image.PixelType, image.Size, image.Metadata, new List<ImageFrameMetadata>(image.Frames.Select(x => x.Metadata)));
ImageMetadata metadata = image.Metadata;
return new(image.Size, metadata, new List<ImageFrameMetadata>(image.Frames.Select(x => x.Metadata)))
{
PixelType = metadata.GetDecodedPixelTypeInfo()
};
}
private static void FromRgba32Bytes<TPixel>(Configuration configuration, Span<byte> rgbaBytes, IMemoryGroup<TPixel> destinationGroup)

94
tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/ReferenceCodecUtilities.cs

@ -0,0 +1,94 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Pbm;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Qoi;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Formats.Webp;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
internal static class ReferenceCodecUtilities
{
/// <summary>
/// Ensures that the metadata is properly initialized for reference and test encoders which cannot initialize
/// metadata in the same manner as our built in decoders.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
/// <param name="image">The decoded image.</param>
/// <param name="format">The image format</param>
/// <exception cref="NotSupportedException">The format is unknown.</exception>
public static Image<TPixel> EnsureDecodedMetadata<TPixel>(Image<TPixel> image, IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel>
{
if (image.Metadata.DecodedImageFormat is null)
{
image.Metadata.DecodedImageFormat = format;
}
foreach (ImageFrame frame in image.Frames)
{
frame.Metadata.DecodedImageFormat = format;
}
switch (format)
{
case BmpFormat:
image.Metadata.GetBmpMetadata();
break;
case GifFormat:
image.Metadata.GetGifMetadata();
foreach (ImageFrame frame in image.Frames)
{
frame.Metadata.GetGifMetadata();
}
break;
case JpegFormat:
image.Metadata.GetJpegMetadata();
break;
case PbmFormat:
image.Metadata.GetPbmMetadata();
break;
case PngFormat:
image.Metadata.GetPngMetadata();
foreach (ImageFrame frame in image.Frames)
{
frame.Metadata.GetPngMetadata();
}
break;
case QoiFormat:
image.Metadata.GetQoiMetadata();
break;
case TgaFormat:
image.Metadata.GetTgaMetadata();
break;
case TiffFormat:
image.Metadata.GetTiffMetadata();
foreach (ImageFrame frame in image.Frames)
{
frame.Metadata.GetTiffMetadata();
}
break;
case WebpFormat:
image.Metadata.GetWebpMetadata();
foreach (ImageFrame frame in image.Frames)
{
frame.Metadata.GetWebpMetadata();
}
break;
}
return image;
}
}

26
tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs

@ -1,23 +1,35 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#pragma warning disable CA1416 // Validate platform compatibility
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SDBitmap = System.Drawing.Bitmap;
using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
public class SystemDrawingReferenceDecoder : ImageDecoder
{
public static SystemDrawingReferenceDecoder Instance { get; } = new SystemDrawingReferenceDecoder();
private readonly IImageFormat imageFormat;
public SystemDrawingReferenceDecoder(IImageFormat imageFormat)
=> this.imageFormat = imageFormat;
public static SystemDrawingReferenceDecoder Png { get; } = new SystemDrawingReferenceDecoder(PngFormat.Instance);
public static SystemDrawingReferenceDecoder Bmp { get; } = new SystemDrawingReferenceDecoder(BmpFormat.Instance);
protected override ImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
using SDBitmap sourceBitmap = new(stream);
PixelTypeInfo pixelType = new(SDImage.GetPixelFormatSize(sourceBitmap.PixelFormat));
return new ImageInfo(pixelType, new(sourceBitmap.Width, sourceBitmap.Height), new ImageMetadata());
using Image<Rgba32> image = this.Decode<Rgba32>(options, stream, cancellationToken);
ImageMetadata metadata = image.Metadata;
return new(image.Size, metadata, new List<ImageFrameMetadata>(image.Frames.Select(x => x.Metadata)))
{
PixelType = metadata.GetDecodedPixelTypeInfo()
};
}
protected override Image<TPixel> Decode<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
@ -42,7 +54,9 @@ public class SystemDrawingReferenceDecoder : ImageDecoder
g.DrawImage(sourceBitmap, 0, 0, sourceBitmap.Width, sourceBitmap.Height);
}
return SystemDrawingBridge.From32bppArgbSystemDrawingBitmap<TPixel>(convertedBitmap);
return ReferenceCodecUtilities.EnsureDecodedMetadata(
SystemDrawingBridge.From32bppArgbSystemDrawingBitmap<TPixel>(convertedBitmap),
this.imageFormat);
}
protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken)

1
tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#pragma warning disable CA1416 // Validate platform compatibility
using System.Drawing.Imaging;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.PixelFormats;

4
tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs

@ -71,13 +71,13 @@ public static partial class TestEnvironment
// Magick codecs should work on all platforms
cfg.ConfigureCodecs(
PngFormat.Instance,
MagickReferenceDecoder.Instance,
MagickReferenceDecoder.Png,
pngEncoder,
new PngImageFormatDetector());
cfg.ConfigureCodecs(
BmpFormat.Instance,
IsWindows ? SystemDrawingReferenceDecoder.Instance : MagickReferenceDecoder.Instance,
IsWindows ? SystemDrawingReferenceDecoder.Bmp : MagickReferenceDecoder.Bmp,
bmpEncoder,
new BmpImageFormatDetector());

15
tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs

@ -7,14 +7,13 @@ using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
using Xunit.Abstractions;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests.TestUtilities.Tests;
public class MagickReferenceCodecTests
{
public MagickReferenceCodecTests(ITestOutputHelper output) => this.Output = output;
private ITestOutputHelper Output { get; }
public ITestOutputHelper Output { get; }
public const PixelTypes PixelTypesToTest32 = PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.Rgb24;
@ -32,8 +31,8 @@ public class MagickReferenceCodecTests
{
string path = TestFile.GetInputFileFullPath(testImage);
var magickDecoder = new MagickReferenceDecoder();
var sdDecoder = new SystemDrawingReferenceDecoder();
MagickReferenceDecoder magickDecoder = MagickReferenceDecoder.Png;
SystemDrawingReferenceDecoder sdDecoder = SystemDrawingReferenceDecoder.Png;
ImageComparer comparer = ImageComparer.Exact;
@ -64,11 +63,11 @@ public class MagickReferenceCodecTests
{
string path = TestFile.GetInputFileFullPath(testImage);
var magickDecoder = new MagickReferenceDecoder();
var sdDecoder = new SystemDrawingReferenceDecoder();
MagickReferenceDecoder magickDecoder = MagickReferenceDecoder.Png;
SystemDrawingReferenceDecoder sdDecoder = SystemDrawingReferenceDecoder.Png;
// 1020 == 4 * 255 (Equivalent to manhattan distance of 1+1+1+1=4 in Rgba32 space)
var comparer = ImageComparer.TolerantPercentage(1, 1020);
// 1020 == 4 * 255 (Equivalent to Manhattan distance of 1+1+1+1=4 in Rgba32 space)
ImageComparer comparer = ImageComparer.TolerantPercentage(1, 1020);
using FileStream mStream = File.OpenRead(path);
using FileStream sdStream = File.OpenRead(path);
using Image<TPixel> mImage = magickDecoder.Decode<TPixel>(DecoderOptions.Default, mStream);

8
tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs

@ -47,7 +47,7 @@ public class ReferenceDecoderBenchmarks
public void BenchmarkMagickPngDecoder<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
this.BenchmarkDecoderImpl(PngBenchmarkFiles, new MagickReferenceDecoder(), "Magick Decode Png");
this.BenchmarkDecoderImpl(PngBenchmarkFiles, MagickReferenceDecoder.Png, "Magick Decode Png");
}
[Theory(Skip = SkipBenchmarks)]
@ -55,7 +55,7 @@ public class ReferenceDecoderBenchmarks
public void BenchmarkSystemDrawingPngDecoder<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
this.BenchmarkDecoderImpl(PngBenchmarkFiles, new SystemDrawingReferenceDecoder(), "System.Drawing Decode Png");
this.BenchmarkDecoderImpl(PngBenchmarkFiles, SystemDrawingReferenceDecoder.Png, "System.Drawing Decode Png");
}
[Theory(Skip = SkipBenchmarks)]
@ -63,7 +63,7 @@ public class ReferenceDecoderBenchmarks
public void BenchmarkMagickBmpDecoder<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
this.BenchmarkDecoderImpl(BmpBenchmarkFiles, new MagickReferenceDecoder(), "Magick Decode Bmp");
this.BenchmarkDecoderImpl(BmpBenchmarkFiles, MagickReferenceDecoder.Bmp, "Magick Decode Bmp");
}
[Theory(Skip = SkipBenchmarks)]
@ -71,7 +71,7 @@ public class ReferenceDecoderBenchmarks
public void BenchmarkSystemDrawingBmpDecoder<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
this.BenchmarkDecoderImpl(BmpBenchmarkFiles, new SystemDrawingReferenceDecoder(), "System.Drawing Decode Bmp");
this.BenchmarkDecoderImpl(BmpBenchmarkFiles, SystemDrawingReferenceDecoder.Bmp, "System.Drawing Decode Bmp");
}
private void BenchmarkDecoderImpl(IEnumerable<string> testFiles, IImageDecoder decoder, string info, int times = DefaultExecutionCount)

2
tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs

@ -93,7 +93,7 @@ public class SystemDrawingReferenceCodecTests
{
string path = TestFile.GetInputFileFullPath(TestImages.Png.Splash);
using FileStream stream = File.OpenRead(path);
using Image<TPixel> image = SystemDrawingReferenceDecoder.Instance.Decode<TPixel>(DecoderOptions.Default, stream);
using Image<TPixel> image = SystemDrawingReferenceDecoder.Png.Decode<TPixel>(DecoderOptions.Default, stream);
image.DebugSave(dummyProvider);
}

26
tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs

@ -3,9 +3,11 @@
using System.Collections.Concurrent;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
using Xunit.Abstractions;
// ReSharper disable InconsistentNaming
@ -25,7 +27,7 @@ public class TestImageProviderTests
TestImageProvider<HalfVector4>.File(TestImages.Bmp.F)
};
public static string[] AllBmpFiles = { TestImages.Bmp.F, TestImages.Bmp.Bit8 };
public static string[] AllBmpFiles = [TestImages.Bmp.F, TestImages.Bmp.Bit8];
public TestImageProviderTests(ITestOutputHelper output) => this.Output = output;
@ -80,9 +82,9 @@ public class TestImageProviderTests
TestDecoder.DoTestThreadSafe(
() =>
{
string testName = nameof(this.GetImage_WithCustomParameterlessDecoder_ShouldUtilizeCache);
const string testName = nameof(this.GetImage_WithCustomParameterlessDecoder_ShouldUtilizeCache);
var decoder = new TestDecoder();
TestDecoder decoder = new();
decoder.InitCaller(testName);
provider.GetImage(decoder);
@ -335,7 +337,7 @@ public class TestImageProviderTests
{
using (provider.GetImage())
{
var customConfiguration = Configuration.CreateDefaultInstance();
Configuration customConfiguration = Configuration.CreateDefaultInstance();
provider.Configuration = customConfiguration;
using Image<TPixel> image2 = provider.GetImage();
@ -365,13 +367,17 @@ public class TestImageProviderTests
protected override ImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
using Image<Rgba32> image = this.Decode<Rgba32>(this.CreateDefaultSpecializedOptions(options), stream, cancellationToken);
return new(image.PixelType, image.Size, image.Metadata, new List<ImageFrameMetadata>(image.Frames.Select(x => x.Metadata)));
ImageMetadata metadata = image.Metadata;
return new(image.Size, metadata, new List<ImageFrameMetadata>(image.Frames.Select(x => x.Metadata)))
{
PixelType = metadata.GetDecodedPixelTypeInfo()
};
}
protected override Image<TPixel> Decode<TPixel>(TestDecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
InvocationCounts[this.callerName]++;
return new Image<TPixel>(42, 42);
return ReferenceCodecUtilities.EnsureDecodedMetadata(new Image<TPixel>(42, 42), PngFormat.Instance);
}
protected override Image Decode(TestDecoderOptions options, Stream stream, CancellationToken cancellationToken)
@ -408,13 +414,17 @@ public class TestImageProviderTests
protected override ImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
using Image<Rgba32> image = this.Decode<Rgba32>(this.CreateDefaultSpecializedOptions(options), stream, cancellationToken);
return new(image.PixelType, image.Size, image.Metadata, new List<ImageFrameMetadata>(image.Frames.Select(x => x.Metadata)));
ImageMetadata metadata = image.Metadata;
return new(image.Size, metadata, new List<ImageFrameMetadata>(image.Frames.Select(x => x.Metadata)))
{
PixelType = metadata.GetDecodedPixelTypeInfo()
};
}
protected override Image<TPixel> Decode<TPixel>(TestDecoderWithParametersOptions options, Stream stream, CancellationToken cancellationToken)
{
InvocationCounts[this.callerName]++;
return new Image<TPixel>(42, 42);
return ReferenceCodecUtilities.EnsureDecodedMetadata(new Image<TPixel>(42, 42), PngFormat.Instance);
}
protected override Image Decode(TestDecoderWithParametersOptions options, Stream stream, CancellationToken cancellationToken)

Loading…
Cancel
Save