diff --git a/tests/ImageSharp.Tests/ComplexIntegrationTests.cs b/tests/ImageSharp.Tests/ComplexIntegrationTests.cs new file mode 100644 index 0000000000..ad4676872f --- /dev/null +++ b/tests/ImageSharp.Tests/ComplexIntegrationTests.cs @@ -0,0 +1,35 @@ +namespace SixLabors.ImageSharp.Tests +{ + using SixLabors.ImageSharp.Formats.Jpeg; + using SixLabors.ImageSharp.PixelFormats; + using SixLabors.ImageSharp.Processing; + using SixLabors.Primitives; + + using Xunit; + + /// + /// Might be useful to catch complex bugs + /// + public class ComplexIntegrationTests + { + [Theory] + [WithFile(TestImages.Jpeg.Baseline.Snake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio420)] + [WithFile(TestImages.Jpeg.Baseline.Lake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio420)] + [WithFile(TestImages.Jpeg.Baseline.Snake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio444)] + [WithFile(TestImages.Jpeg.Baseline.Lake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio444)] + public void LoadResizeSave(TestImageProvider provider, int quality, JpegSubsample subsample) + where TPixel : struct, IPixel + { + using (Image image = provider.GetImage(x => x.Resize(new ResizeOptions { Size = new Size(150, 100), Mode = ResizeMode.Max }))) + { + + image.MetaData.ExifProfile = null; // Reduce the size of the file + JpegEncoder options = new JpegEncoder { Subsample = subsample, Quality = quality }; + + provider.Utility.TestName += $"{subsample}_Q{quality}"; + provider.Utility.SaveTestOutputFile(image, "png"); + provider.Utility.SaveTestOutputFile(image, "jpg", options); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs index c8d416beaf..8610356b56 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs @@ -10,117 +10,126 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg using System.Collections.Generic; using System.IO; + using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.PixelFormats; - using SixLabors.ImageSharp.Processing; - using SixLabors.Primitives; + using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; + using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; using Xunit; using Xunit.Abstractions; - public class JpegEncoderTests : MeasureFixture + public class JpegEncoderTests { - public static IEnumerable AllBmpFiles => TestImages.Bmp.All; + public static readonly TheoryData BitsPerPixel_Quality = + new TheoryData + { + { JpegSubsample.Ratio420, 40 }, + { JpegSubsample.Ratio420, 60 }, + { JpegSubsample.Ratio420, 100 }, + + { JpegSubsample.Ratio444, 40 }, + { JpegSubsample.Ratio444, 60 }, + { JpegSubsample.Ratio444, 100 }, + }; - public JpegEncoderTests(ITestOutputHelper output) - : base(output) + [Theory] + [WithFile(TestImages.Png.CalliphoraPartial, nameof(BitsPerPixel_Quality), PixelTypes.Rgba32)] + [WithTestPatternImages(nameof(BitsPerPixel_Quality), 73, 71, PixelTypes.Rgba32)] + [WithTestPatternImages(nameof(BitsPerPixel_Quality), 48, 24, PixelTypes.Rgba32)] + [WithTestPatternImages(nameof(BitsPerPixel_Quality), 46, 8, PixelTypes.Rgba32)] + [WithTestPatternImages(nameof(BitsPerPixel_Quality), 51, 7, PixelTypes.Rgba32)] + [WithSolidFilledImages(nameof(BitsPerPixel_Quality), 1, 1, 255, 100, 50, 255, PixelTypes.Rgba32)] + [WithTestPatternImages(nameof(BitsPerPixel_Quality), 7, 5, PixelTypes.Rgba32)] + public void EncodeBaseline_WorksWithDifferentSizes(TestImageProvider provider, JpegSubsample subsample, int quality) + where TPixel : struct, IPixel { + TestJpegEncoderCore(provider, subsample, quality); } [Theory] - [WithFile(TestImages.Jpeg.Baseline.Snake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio420)] - [WithFile(TestImages.Jpeg.Baseline.Lake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio420)] - [WithFile(TestImages.Jpeg.Baseline.Snake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio444)] - [WithFile(TestImages.Jpeg.Baseline.Lake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio444)] - public void LoadResizeSave(TestImageProvider provider, int quality, JpegSubsample subsample) + [WithTestPatternImages(nameof(BitsPerPixel_Quality), 48, 48, PixelTypes.Rgba32 | PixelTypes.Bgra32)] + public void EncodeBaseline_IsNotBoundToSinglePixelType(TestImageProvider provider, JpegSubsample subsample, int quality) where TPixel : struct, IPixel { - using (Image image = provider.GetImage(x => x.Resize(new ResizeOptions { Size = new Size(150, 100), Mode = ResizeMode.Max }))) - { - - image.MetaData.ExifProfile = null; // Reduce the size of the file - JpegEncoder options = new JpegEncoder { Subsample = subsample, Quality = quality }; - - provider.Utility.TestName += $"{subsample}_Q{quality}"; - provider.Utility.SaveTestOutputFile(image, "png"); - provider.Utility.SaveTestOutputFile(image, "jpg", options); - } + TestJpegEncoderCore(provider, subsample, quality); } - [Theory] - [WithFileCollection(nameof(AllBmpFiles), PixelTypes.Rgba32 | PixelTypes.Rgba32 | PixelTypes.Argb32, JpegSubsample.Ratio420, 75)] - [WithFileCollection(nameof(AllBmpFiles), PixelTypes.Rgba32 | PixelTypes.Rgba32 | PixelTypes.Argb32, JpegSubsample.Ratio444, 75)] - public void OpenBmp_SaveJpeg(TestImageProvider provider, JpegSubsample subSample, int quality) - where TPixel : struct, IPixel + private static ImageComparer GetComparer(int quality) { - using (Image image = provider.GetImage()) + if (quality > 90) { - ImagingTestCaseUtility utility = provider.Utility; - utility.TestName += "_" + subSample + "_Q" + quality; - - using (FileStream outputStream = File.OpenWrite(utility.GetTestOutputFileName("jpg"))) - { - image.Save(outputStream, new JpegEncoder() - { - Subsample = subSample, - Quality = quality - }); - } + return ImageComparer.Tolerant(0.0005f / 100); + } + else if (quality > 50) + { + return ImageComparer.Tolerant(0.005f / 100); + } + else + { + return ImageComparer.Tolerant(0.01f / 100); } } - [Fact] - public void Encode_IgnoreMetadataIsFalse_ExifProfileIsWritten() + private static void TestJpegEncoderCore( + TestImageProvider provider, + JpegSubsample subsample, + int quality = 100) + where TPixel : struct, IPixel { - JpegEncoder options = new JpegEncoder() - { - IgnoreMetadata = false - }; - - TestFile testFile = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan); - - using (Image input = testFile.CreateImage()) + using (Image image = provider.GetImage()) { - using (MemoryStream memStream = new MemoryStream()) - { - input.Save(memStream, options); - - memStream.Position = 0; - using (Image output = Image.Load(memStream)) - { - Assert.NotNull(output.MetaData.ExifProfile); - } - } + // There is no alpha in Jpeg! + image.Mutate(c => c.Opacity(1)); + + var encoder = new JpegEncoder() + { + Subsample = subsample, + Quality = quality + }; + string info = $"{subsample}-Q{quality}"; + ImageComparer comparer = GetComparer(quality); + + // Does DebugSave & load reference CompareToReferenceInput(): + image.VerifyEncoder(provider, "jpeg", info, encoder, comparer, referenceImageExtension: "png"); } } + - [Fact] - public void Encode_IgnoreMetadataIsTrue_ExifProfileIgnored() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void IgnoreMetadata_ControlsIfExifProfileIsWritten(bool ignoreMetaData) { - JpegEncoder options = new JpegEncoder() + var encoder = new JpegEncoder() { - IgnoreMetadata = true + IgnoreMetadata = ignoreMetaData }; - - TestFile testFile = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan); - - using (Image input = testFile.CreateImage()) + + using (Image input = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateImage()) { - using (MemoryStream memStream = new MemoryStream()) + using (var memStream = new MemoryStream()) { - input.SaveAsJpeg(memStream, options); + input.Save(memStream, encoder); memStream.Position = 0; - using (Image output = Image.Load(memStream)) + using (var output = Image.Load(memStream)) { - Assert.Null(output.MetaData.ExifProfile); + if (ignoreMetaData) + { + Assert.Null(output.MetaData.ExifProfile); + } + else + { + Assert.NotNull(output.MetaData.ExifProfile); + } } } } } - + [Fact] - public void Encode_Quality_0_And_1_Are_Identical() + public void Quality_0_And_1_Are_Identical() { var options = new JpegEncoder { @@ -143,7 +152,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } [Fact] - public void Encode_Quality_0_And_100_Are_Not_Identical() + public void Quality_0_And_100_Are_Not_Identical() { var options = new JpegEncoder { diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index fcc28bf4eb..33dbc911e4 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -352,16 +352,19 @@ namespace SixLabors.ImageSharp.Tests object testOutputDetails, IImageEncoder encoder, ImageComparer customComparer = null, - bool appendPixelTypeToFileName = true + bool appendPixelTypeToFileName = true, + string referenceImageExtension = null ) where TPixel : struct, IPixel { - string path = provider.Utility.SaveTestOutputFile(image, extension, encoder, testOutputDetails, appendPixelTypeToFileName); - - IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(path); - string referenceOutputFile = provider.Utility.GetReferenceOutputFileName(extension, testOutputDetails, appendPixelTypeToFileName); + provider.Utility.SaveTestOutputFile(image, extension, encoder, testOutputDetails, appendPixelTypeToFileName); + referenceImageExtension = referenceImageExtension ?? extension; + string referenceOutputFile = provider.Utility.GetReferenceOutputFileName(referenceImageExtension, testOutputDetails, appendPixelTypeToFileName); + + IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(referenceOutputFile); + using (var encodedImage = Image.Load(referenceOutputFile, referenceDecoder)) { ImageComparer comparer = customComparer ?? ImageComparer.Exact; diff --git a/tests/Images/External b/tests/Images/External index 06809c1f24..550a157d8a 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 06809c1f2462332731f2a88bd866d5222f533aa5 +Subproject commit 550a157d8af7a6883646a010c609f9c7c5c015ac