diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj
index 245af5289c..80cf162c5f 100644
--- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj
+++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj
@@ -19,6 +19,7 @@
+
diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
index d958278f6e..b994af0566 100644
--- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
@@ -30,7 +30,11 @@ public void DecodeBmp(TestImageProvider provider)
using (Image image = provider.GetImage(new BmpDecoder()))
{
image.DebugSave(provider, "bmp");
- image.CompareToOriginal(provider);
+
+ if (TestEnvironment.IsWindows)
+ {
+ image.CompareToOriginal(provider);
+ }
}
}
@@ -52,7 +56,7 @@ public void BmpDecoder_IsNotBoundToSinglePixelType(TestImageProvider(() => decoder.Decode(null, memStream));
+
+ Assert.Equal($"CRC Error. PNG {chunkName} chunk is corrupt!", exception.Message);
+ }
+ }
+
+ [Theory]
+ [InlineData((uint)PngChunkType.Gamma)] // gAMA
+ [InlineData((uint)PngChunkType.PaletteAlpha)] // tRNS
+ [InlineData(
+ (uint)PngChunkType.Physical)] // pHYs: It's ok to test physical as we don't throw for duplicate chunks.
+ //[InlineData(PngChunkTypes.Text)] //TODO: Figure out how to test this
+ public void Decode_IncorrectCRCForNonCriticalChunk_ExceptionIsThrown(uint chunkType)
+ {
+ string chunkName = GetChunkTypeName(chunkType);
+
+ using (var memStream = new MemoryStream())
+ {
+ WriteHeaderChunk(memStream);
+ WriteChunk(memStream, chunkName);
+ WriteDataChunk(memStream);
+
+ var decoder = new PngDecoder();
+ decoder.Decode(null, memStream);
+ }
+ }
+
+ private static string GetChunkTypeName(uint value)
+ {
+ byte[] data = new byte[4];
+
+ BinaryPrimitives.WriteUInt32BigEndian(data, value);
+
+ return Encoding.ASCII.GetString(data);
+ }
+
+ private static void WriteHeaderChunk(MemoryStream memStream)
+ {
+ // Writes a 1x1 32bit png header chunk containing a single black pixel
+ memStream.Write(Raw1X1PngIhdrAndpHYs, 0, Raw1X1PngIhdrAndpHYs.Length);
+ }
+
+ private static void WriteChunk(MemoryStream memStream, string chunkName)
+ {
+ memStream.Write(new byte[] { 0, 0, 0, 1 }, 0, 4);
+ memStream.Write(Encoding.GetEncoding("ASCII").GetBytes(chunkName), 0, 4);
+ memStream.Write(new byte[] { 0, 0, 0, 0, 0 }, 0, 5);
+ }
+
+ private static void WriteDataChunk(MemoryStream memStream)
+ {
+ // Writes a 1x1 32bit png data chunk containing a single black pixel
+ memStream.Write(Raw1X1PngIdatAndIend, 0, Raw1X1PngIdatAndIend.Length);
+ memStream.Position = 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
index 53f71fb7b9..66e4f39fd0 100644
--- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
@@ -1,63 +1,25 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+// ReSharper disable InconsistentNaming
+
+using System.Buffers.Binary;
using System.IO;
using System.Text;
+
+using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
+
using Xunit;
-// ReSharper disable InconsistentNaming
-namespace SixLabors.ImageSharp.Tests
+namespace SixLabors.ImageSharp.Tests.Formats.Png
{
- using System.Buffers.Binary;
- using System.Linq;
-
- using SixLabors.ImageSharp.Formats.Png;
- using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
-
- // TODO: Fix all bugs, and re enable Skipped and commented stuff !!!
- public class PngDecoderTests
+ public partial class PngDecoderTests
{
private const PixelTypes PixelTypes = Tests.PixelTypes.Rgba32 | Tests.PixelTypes.RgbaVector | Tests.PixelTypes.Argb32;
-
- // TODO: Cannot use exact comparer since System.Drawing doesn't preserve more than 32bits.
- private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.1302F, 2134);
-
- // Contains the png marker, IHDR and pHYs chunks of a 1x1 pixel 32bit png 1 a single black pixel.
- private static readonly byte[] raw1x1PngIHDRAndpHYs =
- {
- // PNG Identifier
- 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
-
- // IHDR
- 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00,
- // IHDR CRC
- 0x90, 0x77, 0x53, 0xDE,
-
- // pHYS
- 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0E, 0xC3, 0x00, 0x00, 0x0E, 0xC3, 0x01,
- // pHYS CRC
- 0xC7, 0x6F, 0xA8, 0x64
- };
-
- // Contains the png marker, IDAT and IEND chunks of a 1x1 pixel 32bit png 1 a single black pixel.
- private static readonly byte[] raw1x1PngIDATAndIEND =
- {
- // IDAT
- 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, 0x54, 0x18, 0x57, 0x63, 0x60, 0x60, 0x60, 0x00, 0x00,
- 0x00, 0x04, 0x00, 0x01,
-
- // IDAT CRC
- 0x5C, 0xCD, 0xFF, 0x69,
-
- // IEND
- 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
- 0x4E, 0x44,
-
- // IEND CRC
- 0xAE, 0x42, 0x60, 0x82
- };
+
+
public static readonly string[] CommonTestImages =
{
@@ -105,30 +67,6 @@ public class PngDecoderTests
TestImages.Png.GrayTrns16BitInterlaced
};
- // This is a workaround for Mono-s decoder being incompatible with ours and GDI+.
- // We shouldn't mix these with the Interleaved cases (which are also failing with Mono System.Drawing). Let's go AAA!
- private static readonly string[] SkipOnMono =
- {
- TestImages.Png.Bad.ChunkLength2,
- TestImages.Png.VimImage2,
- TestImages.Png.Splash,
- TestImages.Png.Indexed,
- TestImages.Png.Bad.ChunkLength1,
- TestImages.Png.VersioningImage1,
- TestImages.Png.Banner7Adam7InterlaceMode,
- TestImages.Png.GrayTrns16BitInterlaced,
- TestImages.Png.Rgb48BppInterlaced
- };
-
- private static bool SkipVerification(ITestImageProvider provider)
- {
- string fn = provider.SourceFileOrDescription;
-
- // This is a workaround for Mono-s decoder being incompatible with ours and GDI+.
- // We shouldn't mix these with the Interleaved cases (which are also failing with Mono System.Drawing). Let's go AAA!
- return (TestEnvironment.IsLinux || TestEnvironment.IsMono) && SkipOnMono.Contains(fn);
- }
-
[Theory]
[WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32)]
public void Decode(TestImageProvider provider)
@@ -137,22 +75,7 @@ public void Decode(TestImageProvider provider)
using (Image image = provider.GetImage(new PngDecoder()))
{
image.DebugSave(provider);
-
- if (!SkipVerification(provider))
- {
- image.CompareToOriginal(provider, ImageComparer.Exact);
- }
- }
- }
-
- [Theory]
- [WithFile(TestImages.Png.Interlaced, PixelTypes.Rgba32)]
- public void Decode_Interlaced_DoesNotThrow(TestImageProvider provider)
- where TPixel : struct, IPixel
- {
- using (Image image = provider.GetImage(new PngDecoder()))
- {
- image.DebugSave(provider);
+ image.CompareToOriginal(provider, ImageComparer.Exact);
}
}
@@ -175,12 +98,8 @@ public void Decode_48Bpp(TestImageProvider provider)
{
using (Image image = provider.GetImage(new PngDecoder()))
{
- var encoder = new PngEncoder { ColorType = PngColorType.Rgb, BitDepth = PngBitDepth.Bit16 };
-
- if (!SkipVerification(provider))
- {
- image.VerifyEncoder(provider, "png", null, encoder, customComparer: ValidatorComparer);
- }
+ image.DebugSave(provider);
+ image.CompareToOriginal(provider, ImageComparer.Exact);
}
}
@@ -191,12 +110,8 @@ public void Decode_64Bpp(TestImageProvider provider)
{
using (Image image = provider.GetImage(new PngDecoder()))
{
- var encoder = new PngEncoder { ColorType = PngColorType.RgbWithAlpha, BitDepth = PngBitDepth.Bit16 };
-
- if (!SkipVerification(provider))
- {
- image.VerifyEncoder(provider, "png", null, encoder, customComparer: ValidatorComparer);
- }
+ image.DebugSave(provider);
+ image.CompareToOriginal(provider, ImageComparer.Exact);
}
}
@@ -207,12 +122,8 @@ public void Decode_Gray16Bit(TestImageProvider provider)
{
using (Image image = provider.GetImage(new PngDecoder()))
{
- var encoder = new PngEncoder { ColorType = PngColorType.Grayscale, BitDepth = PngBitDepth.Bit16 };
-
- if (!SkipVerification(provider))
- {
- image.VerifyEncoder(provider, "png", null, encoder, customComparer: ValidatorComparer);
- }
+ image.DebugSave(provider);
+ image.CompareToOriginal(provider, ImageComparer.Exact);
}
}
@@ -223,12 +134,8 @@ public void Decode_GrayAlpha16Bit(TestImageProvider provider)
{
using (Image image = provider.GetImage(new PngDecoder()))
{
- var encoder = new PngEncoder { ColorType = PngColorType.GrayscaleWithAlpha, BitDepth = PngBitDepth.Bit16 };
-
- if (!SkipVerification(provider))
- {
- image.VerifyEncoder(provider, "png", null, encoder, customComparer: ValidatorComparer);
- }
+ image.DebugSave(provider);
+ image.CompareToOriginal(provider, ImageComparer.Exact);
}
}
@@ -303,7 +210,7 @@ public void Decode_TextEncodingSetToUnicode_TextIsReadWithCorrectEncoding()
[InlineData(TestImages.Png.Blur, 32)]
[InlineData(TestImages.Png.Rgb48Bpp, 48)]
[InlineData(TestImages.Png.Rgb48BppInterlaced, 48)]
- public void DetectPixelSize(string imagePath, int expectedPixelSize)
+ public void Identify(string imagePath, int expectedPixelSize)
{
var testFile = TestFile.Create(imagePath);
using (var stream = new MemoryStream(testFile.Bytes, false))
@@ -311,77 +218,5 @@ public void DetectPixelSize(string imagePath, int expectedPixelSize)
Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel);
}
}
-
- [Theory]
- [InlineData((uint)PngChunkType.Header)] // IHDR
- [InlineData((uint)PngChunkType.Palette)] // PLTE
- // [InlineData(PngChunkTypes.Data)] //TODO: Figure out how to test this
- [InlineData((uint)PngChunkType.End)] // IEND
- public void Decode_IncorrectCRCForCriticalChunk_ExceptionIsThrown(uint chunkType)
- {
- string chunkName = GetChunkTypeName(chunkType);
-
- using (var memStream = new MemoryStream())
- {
- WriteHeaderChunk(memStream);
- WriteChunk(memStream, chunkName);
- WriteDataChunk(memStream);
-
- var decoder = new PngDecoder();
-
- ImageFormatException exception = Assert.Throws(() => decoder.Decode(null, memStream));
-
- Assert.Equal($"CRC Error. PNG {chunkName} chunk is corrupt!", exception.Message);
- }
- }
-
- [Theory]
- [InlineData((uint)PngChunkType.Gamma)] // gAMA
- [InlineData((uint)PngChunkType.PaletteAlpha)] // tRNS
- [InlineData((uint)PngChunkType.Physical)] // pHYs: It's ok to test physical as we don't throw for duplicate chunks.
- //[InlineData(PngChunkTypes.Text)] //TODO: Figure out how to test this
- public void Decode_IncorrectCRCForNonCriticalChunk_ExceptionIsThrown(uint chunkType)
- {
- string chunkName = GetChunkTypeName(chunkType);
-
- using (var memStream = new MemoryStream())
- {
- WriteHeaderChunk(memStream);
- WriteChunk(memStream, chunkName);
- WriteDataChunk(memStream);
-
- var decoder = new PngDecoder();
- decoder.Decode(null, memStream);
- }
- }
-
- private static string GetChunkTypeName(uint value)
- {
- byte[] data = new byte[4];
-
- BinaryPrimitives.WriteUInt32BigEndian(data, value);
-
- return Encoding.ASCII.GetString(data);
- }
-
- private static void WriteHeaderChunk(MemoryStream memStream)
- {
- // Writes a 1x1 32bit png header chunk containing a single black pixel
- memStream.Write(raw1x1PngIHDRAndpHYs, 0, raw1x1PngIHDRAndpHYs.Length);
- }
-
- private static void WriteChunk(MemoryStream memStream, string chunkName)
- {
- memStream.Write(new byte[] { 0, 0, 0, 1 }, 0, 4);
- memStream.Write(Encoding.GetEncoding("ASCII").GetBytes(chunkName), 0, 4);
- memStream.Write(new byte[] { 0, 0, 0, 0, 0 }, 0, 5);
- }
-
- private static void WriteDataChunk(MemoryStream memStream)
- {
- // Writes a 1x1 32bit png data chunk containing a single black pixel
- memStream.Write(raw1x1PngIDATAndIEND, 0, raw1x1PngIDATAndIEND.Length);
- memStream.Position = 0;
- }
}
}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
index 4f05f1bdf8..3bcecedec6 100644
--- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
@@ -1,22 +1,21 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+// ReSharper disable InconsistentNaming
using System.IO;
using System.Linq;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Quantization;
+using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using Xunit;
-// ReSharper disable InconsistentNaming
-namespace SixLabors.ImageSharp.Tests
+namespace SixLabors.ImageSharp.Tests.Formats.Png
{
- using SixLabors.ImageSharp.Processing;
- using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
-
public class PngEncoderTests
{
// This is bull. Failing online for no good reason.
@@ -72,7 +71,12 @@ public class PngEncoderTests
public void WorksWithDifferentSizes(TestImageProvider provider, PngColorType pngColorType)
where TPixel : struct, IPixel
{
- TestPngEncoderCore(provider, pngColorType, PngFilterMethod.Adaptive, appendPngColorType: true);
+ TestPngEncoderCore(
+ provider,
+ pngColorType,
+ PngFilterMethod.Adaptive,
+ PngBitDepth.Bit8,
+ appendPngColorType: true);
}
[Theory]
@@ -80,7 +84,13 @@ public void WorksWithDifferentSizes(TestImageProvider provider,
public void IsNotBoundToSinglePixelType(TestImageProvider provider, PngColorType pngColorType)
where TPixel : struct, IPixel
{
- TestPngEncoderCore(provider, pngColorType, PngFilterMethod.Adaptive, appendPixelType: true, appendPngColorType: true);
+ TestPngEncoderCore(
+ provider,
+ pngColorType,
+ PngFilterMethod.Adaptive,
+ PngBitDepth.Bit8,
+ appendPixelType: true,
+ appendPngColorType: true);
}
[Theory]
@@ -88,7 +98,12 @@ public void IsNotBoundToSinglePixelType(TestImageProvider provid
public void WorksWithAllFilterMethods(TestImageProvider provider, PngFilterMethod pngFilterMethod)
where TPixel : struct, IPixel
{
- TestPngEncoderCore(provider, PngColorType.RgbWithAlpha, pngFilterMethod, appendPngFilterMethod: true);
+ TestPngEncoderCore(
+ provider,
+ PngColorType.RgbWithAlpha,
+ pngFilterMethod,
+ PngBitDepth.Bit8,
+ appendPngFilterMethod: true);
}
[Theory]
@@ -96,7 +111,29 @@ public void WorksWithAllFilterMethods(TestImageProvider provider
public void WorksWithAllCompressionLevels(TestImageProvider provider, int compressionLevel)
where TPixel : struct, IPixel
{
- TestPngEncoderCore(provider, PngColorType.RgbWithAlpha, PngFilterMethod.Adaptive, compressionLevel, appendCompressionLevel: true);
+ TestPngEncoderCore(
+ provider,
+ PngColorType.RgbWithAlpha,
+ PngFilterMethod.Adaptive,
+ PngBitDepth.Bit8,
+ compressionLevel,
+ appendCompressionLevel: true);
+ }
+
+ [Theory]
+ [WithTestPatternImages(24, 24, PixelTypes.Rgba64, PngColorType.Rgb)]
+ [WithTestPatternImages(24, 24, PixelTypes.Rgba64, PngColorType.RgbWithAlpha)]
+ [WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.RgbWithAlpha)]
+ public void WorksWithBitDepth16(TestImageProvider provider, PngColorType pngColorType)
+ where TPixel : struct, IPixel
+ {
+ TestPngEncoderCore(
+ provider,
+ pngColorType,
+ PngFilterMethod.Adaptive,
+ PngBitDepth.Bit16,
+ appendPngColorType: true,
+ appendPixelType: true);
}
[Theory]
@@ -104,7 +141,13 @@ public void WorksWithAllCompressionLevels(TestImageProvider prov
public void PaletteColorType_WuQuantizer(TestImageProvider provider, int paletteSize)
where TPixel : struct, IPixel
{
- TestPngEncoderCore(provider, PngColorType.Palette, PngFilterMethod.Adaptive, paletteSize: paletteSize, appendPaletteSize: true);
+ TestPngEncoderCore(
+ provider,
+ PngColorType.Palette,
+ PngFilterMethod.Adaptive,
+ PngBitDepth.Bit8,
+ paletteSize: paletteSize,
+ appendPaletteSize: true);
}
private static bool HasAlpha(PngColorType pngColorType) =>
@@ -114,6 +157,7 @@ private static void TestPngEncoderCore(
TestImageProvider provider,
PngColorType pngColorType,
PngFilterMethod pngFilterMethod,
+ PngBitDepth bitDepth,
int compressionLevel = 6,
int paletteSize = 255,
bool appendPngColorType = false,
@@ -135,6 +179,7 @@ private static void TestPngEncoderCore(
ColorType = pngColorType,
FilterMethod = pngFilterMethod,
CompressionLevel = compressionLevel,
+ BitDepth = bitDepth,
Quantizer = new WuQuantizer(paletteSize)
};
@@ -157,16 +202,31 @@ private static void TestPngEncoderCore(
IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(actualOutputFile);
string referenceOutputFile = ((ITestImageProvider)provider).Utility.GetReferenceOutputFileName("png", debugInfo, appendPixelType, true);
+ bool referenceOutputFileExists = File.Exists(referenceOutputFile);
+
using (var actualImage = Image.Load(actualOutputFile, referenceDecoder))
- using (var referenceImage = Image.Load(referenceOutputFile, referenceDecoder))
{
+ // TODO: Do we still need the reference output files?
+ Image referenceImage = referenceOutputFileExists
+ ? Image.Load(referenceOutputFile, referenceDecoder)
+ : image;
+
float paletteToleranceHack = 80f / paletteSize;
paletteToleranceHack = paletteToleranceHack * paletteToleranceHack;
ImageComparer comparer = pngColorType == PngColorType.Palette
? ImageComparer.Tolerant(ToleranceThresholdForPaletteEncoder * paletteToleranceHack)
: ImageComparer.Exact;
-
- comparer.VerifySimilarity(referenceImage, actualImage);
+ try
+ {
+ comparer.VerifySimilarity(referenceImage, actualImage);
+ }
+ finally
+ {
+ if (referenceOutputFileExists)
+ {
+ referenceImage.Dispose();
+ }
+ }
}
}
}
diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj
index e7e2577a83..9e15b6abad 100644
--- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj
+++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj
@@ -27,6 +27,7 @@
+
diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs
index 2c4eb6c33c..65b32e0880 100644
--- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs
@@ -146,7 +146,6 @@ public string GetTestOutputFileName(
appendSourceFileOrDescription);
}
-
///
/// Encodes image by the format matching the required extension, than saves it to the recommended output file.
///
@@ -154,7 +153,9 @@ public string GetTestOutputFileName(
/// The image instance
/// The requested extension
/// Optional encoder
- /// /// A boolean indicating whether to append to the test output file name.
+ /// A value indicating whether to append the pixel type to the test output file name
+ /// A boolean indicating whether to append to the test output file name.
+ /// Additional information to append to the test output file name
public string SaveTestOutputFile(
Image image,
string extension = null,
@@ -176,6 +177,7 @@ public string SaveTestOutputFile(
{
image.Save(stream, encoder);
}
+
return path;
}
diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs
new file mode 100644
index 0000000000..8cfc2472f5
--- /dev/null
+++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs
@@ -0,0 +1,53 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+
+using ImageMagick;
+
+using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Formats;
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
+{
+ public class MagickReferenceDecoder : IImageDecoder
+ {
+ public static MagickReferenceDecoder Instance { get; } = new MagickReferenceDecoder();
+
+ public Image Decode(Configuration configuration, Stream stream)
+ where TPixel : struct, IPixel
+ {
+ using (var magickImage = new MagickImage(stream))
+ {
+ var result = new Image(configuration, magickImage.Width, magickImage.Height);
+ Span resultPixels = result.GetPixelSpan();
+
+ using (IPixelCollection pixels = magickImage.GetPixelsUnsafe())
+ {
+ if (magickImage.Depth == 8)
+ {
+ byte[] data = pixels.ToByteArray("RGBA");
+
+ PixelOperations.Instance.PackFromRgba32Bytes(data, resultPixels, resultPixels.Length);
+ }
+ else if (magickImage.Depth == 16)
+ {
+ ushort[] data = pixels.ToShortArray("RGBA");
+ Span bytes = MemoryMarshal.Cast(data.AsSpan());
+
+ PixelOperations.Instance.PackFromRgba64Bytes(bytes, resultPixels, resultPixels.Length);
+ }
+ else
+ {
+ throw new InvalidOperationException();
+ }
+ }
+
+ return result;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs
index 9123336955..46dae17a11 100644
--- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs
@@ -20,6 +20,8 @@ public SystemDrawingReferenceEncoder(ImageFormat imageFormat)
public static SystemDrawingReferenceEncoder Png { get; } = new SystemDrawingReferenceEncoder(ImageFormat.Png);
+ public static SystemDrawingReferenceEncoder Bmp { get; } = new SystemDrawingReferenceEncoder(ImageFormat.Bmp);
+
public void Encode(Image image, Stream stream)
where TPixel : struct, IPixel
{
diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs
index 566c22342c..90c999f7cd 100644
--- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs
@@ -14,9 +14,9 @@ namespace SixLabors.ImageSharp.Tests
{
public static partial class TestEnvironment
{
- private static Lazy configuration = new Lazy(CreateDefaultConfiguration);
+ private static readonly Lazy ConfigurationLazy = new Lazy(CreateDefaultConfiguration);
- internal static Configuration Configuration => configuration.Value;
+ internal static Configuration Configuration => ConfigurationLazy.Value;
internal static IImageDecoder GetReferenceDecoder(string filePath)
{
@@ -52,36 +52,28 @@ private static void ConfigureCodecs(
private static Configuration CreateDefaultConfiguration()
{
- var configuration = new Configuration(
- new PngConfigurationModule(),
+ var cfg = new Configuration(
new JpegConfigurationModule(),
new GifConfigurationModule()
);
- if (!IsLinux)
- {
- // TODO: System.Drawing on Windows can decode 48bit and 64bit pngs but
- // it doesn't preserve the accuracy we require for comparison.
- // This makes CompareToOriginal method non-useful.
- configuration.ConfigureCodecs(
- ImageFormats.Png,
- SystemDrawingReferenceDecoder.Instance,
- SystemDrawingReferenceEncoder.Png,
- new PngImageFormatDetector());
+ // Magick codecs should work on all platforms
+ IImageEncoder pngEncoder = IsWindows ? (IImageEncoder)SystemDrawingReferenceEncoder.Png : new PngEncoder();
+ IImageEncoder bmpEncoder = IsWindows ? (IImageEncoder)SystemDrawingReferenceEncoder.Bmp : new BmpEncoder();
- configuration.ConfigureCodecs(
- ImageFormats.Bmp,
- SystemDrawingReferenceDecoder.Instance,
- SystemDrawingReferenceEncoder.Png,
- new PngImageFormatDetector());
- }
- else
- {
- configuration.Configure(new PngConfigurationModule());
- configuration.Configure(new BmpConfigurationModule());
- }
+ cfg.ConfigureCodecs(
+ ImageFormats.Png,
+ MagickReferenceDecoder.Instance,
+ pngEncoder,
+ new PngImageFormatDetector());
- return configuration;
+ cfg.ConfigureCodecs(
+ ImageFormats.Bmp,
+ SystemDrawingReferenceDecoder.Instance,
+ bmpEncoder,
+ new BmpImageFormatDetector());
+
+ return cfg;
}
}
}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs
index 9a41e66025..a5a3e332c7 100644
--- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs
@@ -21,9 +21,9 @@ public static partial class TestEnvironment
private const string ToolsDirectoryRelativePath = @"tests\Images\External\tools";
- private static Lazy solutionDirectoryFullPath = new Lazy(GetSolutionDirectoryFullPathImpl);
+ private static readonly Lazy SolutionDirectoryFullPathLazy = new Lazy(GetSolutionDirectoryFullPathImpl);
- private static Lazy runsOnCi = new Lazy(
+ private static readonly Lazy RunsOnCiLazy = new Lazy(
() =>
{
bool isCi;
@@ -41,9 +41,9 @@ public static partial class TestEnvironment
///
/// Gets a value indicating whether test execution runs on CI.
///
- internal static bool RunsOnCI => runsOnCi.Value;
+ internal static bool RunsOnCI => RunsOnCiLazy.Value;
- internal static string SolutionDirectoryFullPath => solutionDirectoryFullPath.Value;
+ internal static string SolutionDirectoryFullPath => SolutionDirectoryFullPathLazy.Value;
private static string GetSolutionDirectoryFullPathImpl()
{
@@ -65,6 +65,7 @@ private static string GetSolutionDirectoryFullPathImpl()
$"Unable to find ImageSharp solution directory from {assemblyLocation} because of {ex.GetType().Name}!",
ex);
}
+
if (directory == null)
{
throw new Exception($"Unable to find ImageSharp solution directory from {assemblyLocation}!");
@@ -116,7 +117,7 @@ internal static string GetReferenceOutputFileName(string actualOutputFileName) =
///
internal static string CreateOutputDirectory(string path, params string[] pathParts)
{
- path = Path.Combine(TestEnvironment.ActualOutputDirectoryFullPath, path);
+ path = Path.Combine(ActualOutputDirectoryFullPath, path);
if (pathParts != null && pathParts.Length > 0)
{
diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs
index 016ae7ad29..a1f97afb9c 100644
--- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs
@@ -499,16 +499,18 @@ public static ImageFrame ComparePixelBufferTo(
public static Image CompareToOriginal(
this Image image,
- ITestImageProvider provider)
+ ITestImageProvider provider,
+ IImageDecoder referenceDecoder = null)
where TPixel : struct, IPixel
{
- return CompareToOriginal(image, provider, ImageComparer.Tolerant());
+ return CompareToOriginal(image, provider, ImageComparer.Tolerant(), referenceDecoder);
}
public static Image CompareToOriginal(
this Image image,
ITestImageProvider provider,
- ImageComparer comparer)
+ ImageComparer comparer,
+ IImageDecoder referenceDecoder = null)
where TPixel : struct, IPixel
{
string path = TestImageProvider.GetFilePathOrNull(provider);
@@ -519,15 +521,8 @@ public static Image CompareToOriginal(
var testFile = TestFile.Create(path);
- IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(path);
- IImageFormat format = TestEnvironment.GetImageFormat(path);
- IImageDecoder defaultDecoder = Configuration.Default.ImageFormatsManager.FindDecoder(format);
-
- //if (referenceDecoder.GetType() == defaultDecoder.GetType())
- //{
- // throw new InvalidOperationException($"Can't use CompareToOriginal(): no actual reference decoder registered for {format.Name}");
- //}
-
+ referenceDecoder = referenceDecoder ?? TestEnvironment.GetReferenceDecoder(path);
+
using (var original = Image.Load(testFile.Bytes, referenceDecoder))
{
comparer.VerifySimilarity(original, image);
@@ -641,7 +636,8 @@ internal static void VerifyEncoder(
IImageEncoder encoder,
ImageComparer customComparer = null,
bool appendPixelTypeToFileName = true,
- string referenceImageExtension = null)
+ string referenceImageExtension = null,
+ IImageDecoder referenceDecoder = null)
where TPixel : struct, IPixel
{
string actualOutputFile = provider.Utility.SaveTestOutputFile(
@@ -650,7 +646,8 @@ internal static void VerifyEncoder(
encoder,
testOutputDetails,
appendPixelTypeToFileName);
- IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(actualOutputFile);
+
+ referenceDecoder = referenceDecoder ?? TestEnvironment.GetReferenceDecoder(actualOutputFile);
using (var actualImage = Image.Load(actualOutputFile, referenceDecoder))
{
diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs
new file mode 100644
index 0000000000..db651886f2
--- /dev/null
+++ b/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs
@@ -0,0 +1,89 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using Xunit;
+// ReSharper disable InconsistentNaming
+
+namespace SixLabors.ImageSharp.Tests.TestUtilities.Tests
+{
+ using SixLabors.ImageSharp.PixelFormats;
+ using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
+ using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
+
+ using Xunit.Abstractions;
+
+ public class MagickReferenceCodecTests
+ {
+ public MagickReferenceCodecTests(ITestOutputHelper output)
+ {
+ this.Output = output;
+ }
+
+ private ITestOutputHelper Output { get; }
+
+ public const PixelTypes PixelTypesToTest32 = PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.Rgb24;
+
+ public const PixelTypes PixelTypesToTest64 =
+ PixelTypes.Rgba32 | PixelTypes.Rgb24 | PixelTypes.Rgba64 | PixelTypes.Rgb48;
+
+ public const PixelTypes PixelTypesToTest48 =
+ PixelTypes.Rgba32 | PixelTypes.Rgba64 | PixelTypes.Rgb48;
+
+ [Theory]
+ [WithBlankImages(1, 1, PixelTypesToTest32, TestImages.Png.Splash)]
+ [WithBlankImages(1, 1, PixelTypesToTest32, TestImages.Png.Indexed)]
+ public void MagickDecode_8BitDepthImage_IsEquivalentTo_SystemDrawingResult(TestImageProvider dummyProvider, string testImage)
+ where TPixel : struct, IPixel
+ {
+ string path = TestFile.GetInputFileFullPath(testImage);
+
+ var magickDecoder = new MagickReferenceDecoder();
+ var sdDecoder = new SystemDrawingReferenceDecoder();
+
+ ImageComparer comparer = ImageComparer.Exact;
+
+ using (var mImage = Image.Load(path, magickDecoder))
+ using (var sdImage = Image.Load(path, sdDecoder))
+ {
+ ImageSimilarityReport report = comparer.CompareImagesOrFrames(mImage, sdImage);
+
+ mImage.DebugSave(dummyProvider);
+
+ if (TestEnvironment.IsWindows)
+ {
+ Assert.True(report.IsEmpty);
+ }
+ }
+ }
+
+ [Theory]
+ [WithBlankImages(1, 1, PixelTypesToTest64, TestImages.Png.Rgba64Bpp)]
+ [WithBlankImages(1, 1, PixelTypesToTest48, TestImages.Png.Rgb48Bpp)]
+ [WithBlankImages(1, 1, PixelTypesToTest48, TestImages.Png.Rgb48BppInterlaced)]
+ [WithBlankImages(1, 1, PixelTypesToTest48, TestImages.Png.Rgb48BppTrans)]
+ public void MagickDecode_16BitDepthImage_IsApproximatelyEquivalentTo_SystemDrawingResult(TestImageProvider dummyProvider, string testImage)
+ where TPixel : struct, IPixel
+ {
+ string path = TestFile.GetInputFileFullPath(testImage);
+
+ var magickDecoder = new MagickReferenceDecoder();
+ var sdDecoder = new SystemDrawingReferenceDecoder();
+
+ // 1020 == 4 * 255 (Equivalent to manhattan distance of 1+1+1+1=4 in Rgba32 space)
+ var comparer = ImageComparer.TolerantPercentage(1, 1020);
+
+ using (var mImage = Image.Load(path, magickDecoder))
+ using (var sdImage = Image.Load(path, sdDecoder))
+ {
+ ImageSimilarityReport report = comparer.CompareImagesOrFrames(mImage, sdImage);
+
+ mImage.DebugSave(dummyProvider);
+
+ if (TestEnvironment.IsWindows)
+ {
+ Assert.True(report.IsEmpty);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs
new file mode 100644
index 0000000000..724c2e4144
--- /dev/null
+++ b/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs
@@ -0,0 +1,96 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.Collections.Generic;
+
+using SixLabors.ImageSharp.Formats;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
+
+using Xunit;
+using Xunit.Abstractions;
+
+namespace SixLabors.ImageSharp.Tests.TestUtilities.Tests
+{
+ public class ReferenceDecoderBenchmarks
+ {
+ private ITestOutputHelper Output { get; }
+
+ public const string SkipBenchmarks =
+#if false
+ "Benchmark, enable manually!";
+#else
+ null;
+#endif
+
+ public const int DefaultExecutionCount = 50;
+
+ public static readonly string[] PngBenchmarkFiles =
+ {
+ TestImages.Png.CalliphoraPartial,
+ TestImages.Png.Kaboom,
+ TestImages.Png.Bike,
+ TestImages.Png.Splash,
+ TestImages.Png.SplashInterlaced
+ };
+
+ public static readonly string[] BmpBenchmarkFiles =
+ {
+ TestImages.Bmp.NegHeight,
+ TestImages.Bmp.Car,
+ TestImages.Bmp.V5Header
+ };
+
+ public ReferenceDecoderBenchmarks(ITestOutputHelper output)
+ {
+ this.Output = output;
+ }
+
+ [Theory(Skip = SkipBenchmarks)]
+ [WithFile(TestImages.Png.Kaboom, PixelTypes.Rgba32)]
+ public void BenchmarkMagickPngDecoder(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ this.BenckmarkDecoderImpl(PngBenchmarkFiles, new MagickReferenceDecoder(), $@"Magick Decode Png");
+ }
+
+ [Theory(Skip = SkipBenchmarks)]
+ [WithFile(TestImages.Png.Kaboom, PixelTypes.Rgba32)]
+ public void BenchmarkSystemDrawingPngDecoder(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ this.BenckmarkDecoderImpl(PngBenchmarkFiles, new SystemDrawingReferenceDecoder(), $@"System.Drawing Decode Png");
+ }
+
+ [Theory(Skip = SkipBenchmarks)]
+ [WithFile(TestImages.Png.Kaboom, PixelTypes.Rgba32)]
+ public void BenchmarkMagickBmpDecoder(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ this.BenckmarkDecoderImpl(BmpBenchmarkFiles, new MagickReferenceDecoder(), $@"Magick Decode Bmp");
+ }
+
+ [Theory(Skip = SkipBenchmarks)]
+ [WithFile(TestImages.Png.Kaboom, PixelTypes.Rgba32)]
+ public void BenchmarkSystemDrawingBmpDecoder(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ this.BenckmarkDecoderImpl(BmpBenchmarkFiles, new SystemDrawingReferenceDecoder(), $@"System.Drawing Decode Bmp");
+ }
+
+ private void BenckmarkDecoderImpl(IEnumerable testFiles, IImageDecoder decoder, string info, int times = DefaultExecutionCount)
+ {
+ var measure = new MeasureFixture(this.Output);
+ measure.Measure(times,
+ () =>
+ {
+ foreach (string testFile in testFiles)
+ {
+ Image image = TestFile.Create(testFile).CreateImage(decoder);
+ image.Dispose();
+ }
+ },
+ info);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceCodecTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs
similarity index 94%
rename from tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceCodecTests.cs
rename to tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs
index 3ad595b7e4..3cdb67dbdb 100644
--- a/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceCodecTests.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs
@@ -1,4 +1,6 @@
-using System.IO;
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
@@ -8,13 +10,13 @@
using Xunit;
using Xunit.Abstractions;
-namespace SixLabors.ImageSharp.Tests
+namespace SixLabors.ImageSharp.Tests.TestUtilities.Tests
{
- public class ReferenceCodecTests
+ public class SystemDrawingReferenceCodecTests
{
private ITestOutputHelper Output { get; }
- public ReferenceCodecTests(ITestOutputHelper output)
+ public SystemDrawingReferenceCodecTests(ITestOutputHelper output)
{
this.Output = output;
}
diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs
index f6d3bdb7b9..8a3e69059f 100644
--- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs
@@ -18,7 +18,6 @@
namespace SixLabors.ImageSharp.Tests
{
-
public class TestEnvironmentTests
{
public TestEnvironmentTests(ITestOutputHelper output)
@@ -99,7 +98,7 @@ public void GetReferenceEncoder_ReturnsCorrectEncoders_Windows(string fileName,
}
[Theory]
- [InlineData("lol/foo.png", typeof(SystemDrawingReferenceDecoder))]
+ [InlineData("lol/foo.png", typeof(MagickReferenceDecoder))]
[InlineData("lol/Rofl.bmp", typeof(SystemDrawingReferenceDecoder))]
[InlineData("lol/Baz.JPG", typeof(JpegDecoder))]
[InlineData("lol/Baz.gif", typeof(GifDecoder))]
@@ -125,8 +124,8 @@ public void GetReferenceEncoder_ReturnsCorrectEncoders_Linux(string fileName, Ty
}
[Theory]
- [InlineData("lol/foo.png", typeof(PngDecoder))]
- [InlineData("lol/Rofl.bmp", typeof(BmpDecoder))]
+ [InlineData("lol/foo.png", typeof(MagickReferenceDecoder))]
+ [InlineData("lol/Rofl.bmp", typeof(SystemDrawingReferenceDecoder))]
[InlineData("lol/Baz.JPG", typeof(JpegDecoder))]
[InlineData("lol/Baz.gif", typeof(GifDecoder))]
public void GetReferenceDecoder_ReturnsCorrectDecoders_Linux(string fileName, Type expectedDecoderType)
diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs
index 06c77235b2..02acdfa183 100644
--- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs
@@ -241,7 +241,11 @@ public void GetImage_WithCustomParametricDecoder_ShouldNotUtilizeCache_WhenParam
}
- public static string[] AllBmpFiles => TestImages.Bmp.All;
+ public static string[] AllBmpFiles =
+ {
+ TestImages.Bmp.F,
+ TestImages.Bmp.Bit8
+ };
[Theory]
[WithFileCollection(nameof(AllBmpFiles), PixelTypes.Rgba32 | PixelTypes.Argb32)]