From af7c3c509c6dcc2359ad36e21749a59b20ba0ceb Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sun, 21 Nov 2021 04:38:12 +0300 Subject: [PATCH 1/7] Added generic benchmark --- .../Codecs/Jpeg/DecodeJpeg.cs | 81 +++++++++++++++++++ .../Formats/Jpg/JpegDecoderTests.Metadata.cs | 2 +- tests/ImageSharp.Tests/TestImages.cs | 3 +- .../Jpg/baseline/winter444_interleaved.jpg | 3 + ...inter.jpg => winter420_noninterleaved.jpg} | 0 5 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs create mode 100644 tests/Images/Input/Jpg/baseline/winter444_interleaved.jpg rename tests/Images/Input/Jpg/progressive/{winter.jpg => winter420_noninterleaved.jpg} (100%) diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs new file mode 100644 index 0000000000..7a878738d6 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs @@ -0,0 +1,81 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.IO; +using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.Tests; + +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg +{ + public class DecodeJpeg + { + private JpegDecoder decoder; + + private MemoryStream preloadedImageStream; + + private void GenericSetup(string imageSubpath) + { + this.decoder = new JpegDecoder(); + byte[] bytes = File.ReadAllBytes(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, imageSubpath)); + this.preloadedImageStream = new MemoryStream(bytes); + } + + private void GenericBechmark() + { + this.preloadedImageStream.Position = 0; + using Image img = this.decoder.Decode(Configuration.Default, this.preloadedImageStream); + } + + [GlobalSetup(Target = nameof(JpegBaselineInterleaved444))] + public void SetupBaselineInterleaved444() => + this.GenericSetup(TestImages.Jpeg.Baseline.Winter444_Interleaved); + + [GlobalSetup(Target = nameof(JpegBaselineInterleaved420))] + public void SetupBaselineInterleaved420() => + this.GenericSetup(TestImages.Jpeg.Baseline.Hiyamugi); + + [GlobalSetup(Target = nameof(JpegBaseline400))] + public void SetupBaselineSingleComponent() => + this.GenericSetup(TestImages.Jpeg.Baseline.Jpeg400); + + [GlobalSetup(Target = nameof(JpegProgressiveNonInterleaved420))] + public void SetupProgressiveNoninterleaved420() => + this.GenericSetup(TestImages.Jpeg.Progressive.Winter420_NonInterleaved); + + [GlobalCleanup] + public void Cleanup() + { + this.preloadedImageStream.Dispose(); + this.preloadedImageStream = null; + } + + [Benchmark(Description = "Baseline 4:4:4 Interleaved")] + public void JpegBaselineInterleaved444() => this.GenericBechmark(); + + [Benchmark(Description = "Baseline 4:2:0 Interleaved")] + public void JpegBaselineInterleaved420() => this.GenericBechmark(); + + [Benchmark(Description = "Baseline 4:0:0 (grayscale)")] + public void JpegBaseline400() => this.GenericBechmark(); + + [Benchmark(Description = "Progressive 4:2:0 Non-Interleaved")] + public void JpegProgressiveNonInterleaved420() => this.GenericBechmark(); + } +} + + +/* +BenchmarkDotNet=v0.13.0, OS=Windows 10.0.19042.1288 (20H2/October2020Update) +Intel Core i7-6700K CPU 4.00GHz (Skylake), 1 CPU, 8 logical and 4 physical cores +.NET SDK=6.0.100-preview.3.21202.5 + [Host] : .NET Core 3.1.18 (CoreCLR 4.700.21.35901, CoreFX 4.700.21.36305), X64 RyuJIT + DefaultJob : .NET Core 3.1.18 (CoreCLR 4.700.21.35901, CoreFX 4.700.21.36305), X64 RyuJIT +MASTER +| Method | Mean | Error | StdDev | +|------------------------------------ |----------:|----------:|----------:| +| 'Baseline 4:4:4 Interleaved' | 12.710 ms | 0.1120 ms | 0.0990 ms | +| 'Baseline 4:2:0 Interleaved' | 8.855 ms | 0.1447 ms | 0.1353 ms | +| 'Baseline 4:0:0 (grayscale)' | 1.660 ms | 0.0106 ms | 0.0088 ms | +| 'Progressive 4:2:0 Non-Interleaved' | 14.138 ms | 0.2797 ms | 0.3330 ms | +*/ diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs index 5e42c6c8fc..7b3e20aa2a 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { TestImages.Jpeg.Progressive.Fb, 75 }, { TestImages.Jpeg.Issues.IncorrectQuality845, 98 }, { TestImages.Jpeg.Baseline.ForestBridgeDifferentComponentsQuality, 89 }, - { TestImages.Jpeg.Progressive.Winter, 80 } + { TestImages.Jpeg.Progressive.Winter420_NonInterleaved, 80 } }; [Theory] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 116c5adc34..e003649135 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -163,7 +163,7 @@ namespace SixLabors.ImageSharp.Tests public const string Fb = "Jpg/progressive/fb.jpg"; public const string Progress = "Jpg/progressive/progress.jpg"; public const string Festzug = "Jpg/progressive/Festzug.jpg"; - public const string Winter = "Jpg/progressive/winter.jpg"; + public const string Winter420_NonInterleaved = "Jpg/progressive/winter420_noninterleaved.jpg"; public static class Bad { @@ -213,6 +213,7 @@ namespace SixLabors.ImageSharp.Tests public const string ArithmeticCoding = "Jpg/baseline/arithmetic_coding.jpg"; public const string ArithmeticCodingProgressive = "Jpg/progressive/arithmetic_progressive.jpg"; public const string Lossless = "Jpg/baseline/lossless.jpg"; + public const string Winter444_Interleaved = "Jpg/baseline/winter444_interleaved.jpg"; public static readonly string[] All = { diff --git a/tests/Images/Input/Jpg/baseline/winter444_interleaved.jpg b/tests/Images/Input/Jpg/baseline/winter444_interleaved.jpg new file mode 100644 index 0000000000..9ae834389f --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/winter444_interleaved.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:73b1deb4e2fb8027f6bb4fb293e5b2615c80b3ac0a7f99fd90118fd340a9fd12 +size 283330 diff --git a/tests/Images/Input/Jpg/progressive/winter.jpg b/tests/Images/Input/Jpg/progressive/winter420_noninterleaved.jpg similarity index 100% rename from tests/Images/Input/Jpg/progressive/winter.jpg rename to tests/Images/Input/Jpg/progressive/winter420_noninterleaved.jpg From cdb2a648a6cdc2061ee399ceae4a96e7e9b59f3b Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sun, 21 Nov 2021 04:47:37 +0300 Subject: [PATCH 2/7] Structured benchmark files --- tests/ImageSharp.Benchmarks/Codecs/{ => Bmp}/DecodeBmp.cs | 0 tests/ImageSharp.Benchmarks/Codecs/{ => Bmp}/EncodeBmp.cs | 0 tests/ImageSharp.Benchmarks/Codecs/{ => Bmp}/EncodeBmpMultiple.cs | 0 tests/ImageSharp.Benchmarks/Codecs/{ => Gif}/DecodeGif.cs | 0 tests/ImageSharp.Benchmarks/Codecs/{ => Gif}/EncodeGif.cs | 0 tests/ImageSharp.Benchmarks/Codecs/{ => Gif}/EncodeGifMultiple.cs | 0 .../Codecs/Jpeg/{ => ColorConversion}/CmykColorConversion.cs | 0 .../Codecs/Jpeg/{ => ColorConversion}/ColorConversionBenchmark.cs | 0 .../Codecs/Jpeg/{ => ColorConversion}/GrayscaleColorConversion.cs | 0 .../Codecs/Jpeg/{ => ColorConversion}/RgbColorConversion.cs | 0 .../Codecs/Jpeg/{ => ColorConversion}/YCbCrColorConversion.cs | 0 .../Jpeg/ColorConversion}/YCbCrForwardConverterBenchmark.cs | 0 .../Codecs/Jpeg/{ => ColorConversion}/YccKColorConverter.cs | 0 tests/ImageSharp.Benchmarks/Codecs/{ => Png}/DecodeFilteredPng.cs | 0 tests/ImageSharp.Benchmarks/Codecs/{ => Png}/DecodePng.cs | 0 tests/ImageSharp.Benchmarks/Codecs/{ => Png}/EncodeIndexedPng.cs | 0 tests/ImageSharp.Benchmarks/Codecs/{ => Png}/EncodePng.cs | 0 tests/ImageSharp.Benchmarks/Codecs/{ => Tga}/DecodeTga.cs | 0 tests/ImageSharp.Benchmarks/Codecs/{ => Tga}/EncodeTga.cs | 0 tests/ImageSharp.Benchmarks/Codecs/{ => Tiff}/DecodeTiff.cs | 0 tests/ImageSharp.Benchmarks/Codecs/{ => Tiff}/EncodeTiff.cs | 0 tests/ImageSharp.Benchmarks/Codecs/{ => Webp}/DecodeWebp.cs | 0 tests/ImageSharp.Benchmarks/Codecs/{ => Webp}/EncodeWebp.cs | 0 23 files changed, 0 insertions(+), 0 deletions(-) rename tests/ImageSharp.Benchmarks/Codecs/{ => Bmp}/DecodeBmp.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/{ => Bmp}/EncodeBmp.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/{ => Bmp}/EncodeBmpMultiple.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/{ => Gif}/DecodeGif.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/{ => Gif}/EncodeGif.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/{ => Gif}/EncodeGifMultiple.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/Jpeg/{ => ColorConversion}/CmykColorConversion.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/Jpeg/{ => ColorConversion}/ColorConversionBenchmark.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/Jpeg/{ => ColorConversion}/GrayscaleColorConversion.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/Jpeg/{ => ColorConversion}/RgbColorConversion.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/Jpeg/{ => ColorConversion}/YCbCrColorConversion.cs (100%) rename tests/ImageSharp.Benchmarks/{Format/Jpeg/Components/Encoder => Codecs/Jpeg/ColorConversion}/YCbCrForwardConverterBenchmark.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/Jpeg/{ => ColorConversion}/YccKColorConverter.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/{ => Png}/DecodeFilteredPng.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/{ => Png}/DecodePng.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/{ => Png}/EncodeIndexedPng.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/{ => Png}/EncodePng.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/{ => Tga}/DecodeTga.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/{ => Tga}/EncodeTga.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/{ => Tiff}/DecodeTiff.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/{ => Tiff}/EncodeTiff.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/{ => Webp}/DecodeWebp.cs (100%) rename tests/ImageSharp.Benchmarks/Codecs/{ => Webp}/EncodeWebp.cs (100%) diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeBmp.cs b/tests/ImageSharp.Benchmarks/Codecs/Bmp/DecodeBmp.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/DecodeBmp.cs rename to tests/ImageSharp.Benchmarks/Codecs/Bmp/DecodeBmp.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeBmp.cs b/tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmp.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/EncodeBmp.cs rename to tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmp.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeBmpMultiple.cs b/tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmpMultiple.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/EncodeBmpMultiple.cs rename to tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmpMultiple.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeGif.cs b/tests/ImageSharp.Benchmarks/Codecs/Gif/DecodeGif.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/DecodeGif.cs rename to tests/ImageSharp.Benchmarks/Codecs/Gif/DecodeGif.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs b/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGif.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs rename to tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGif.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs b/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGifMultiple.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs rename to tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGifMultiple.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/CmykColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/Jpeg/CmykColorConversion.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversionBenchmark.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/ColorConversionBenchmark.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversionBenchmark.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/ColorConversionBenchmark.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/GrayscaleColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/Jpeg/GrayscaleColorConversion.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/RgbColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/Jpeg/RgbColorConversion.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs diff --git a/tests/ImageSharp.Benchmarks/Format/Jpeg/Components/Encoder/YCbCrForwardConverterBenchmark.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrForwardConverterBenchmark.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Format/Jpeg/Components/Encoder/YCbCrForwardConverterBenchmark.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrForwardConverterBenchmark.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YccKColorConverter.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/Jpeg/YccKColorConverter.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeFilteredPng.cs b/tests/ImageSharp.Benchmarks/Codecs/Png/DecodeFilteredPng.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/DecodeFilteredPng.cs rename to tests/ImageSharp.Benchmarks/Codecs/Png/DecodeFilteredPng.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodePng.cs b/tests/ImageSharp.Benchmarks/Codecs/Png/DecodePng.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/DecodePng.cs rename to tests/ImageSharp.Benchmarks/Codecs/Png/DecodePng.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs b/tests/ImageSharp.Benchmarks/Codecs/Png/EncodeIndexedPng.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs rename to tests/ImageSharp.Benchmarks/Codecs/Png/EncodeIndexedPng.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodePng.cs b/tests/ImageSharp.Benchmarks/Codecs/Png/EncodePng.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/EncodePng.cs rename to tests/ImageSharp.Benchmarks/Codecs/Png/EncodePng.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs b/tests/ImageSharp.Benchmarks/Codecs/Tga/DecodeTga.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs rename to tests/ImageSharp.Benchmarks/Codecs/Tga/DecodeTga.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeTga.cs b/tests/ImageSharp.Benchmarks/Codecs/Tga/EncodeTga.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/EncodeTga.cs rename to tests/ImageSharp.Benchmarks/Codecs/Tga/EncodeTga.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeTiff.cs b/tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/DecodeTiff.cs rename to tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeTiff.cs b/tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/EncodeTiff.cs rename to tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs b/tests/ImageSharp.Benchmarks/Codecs/Webp/DecodeWebp.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs rename to tests/ImageSharp.Benchmarks/Codecs/Webp/DecodeWebp.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeWebp.cs b/tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs similarity index 100% rename from tests/ImageSharp.Benchmarks/Codecs/EncodeWebp.cs rename to tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs From e143093d98c38082d64e7c0e83d0793fd7c50e8a Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sun, 21 Nov 2021 04:52:40 +0300 Subject: [PATCH 3/7] Removed excess comment --- tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs index 7a878738d6..842eea685a 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs @@ -71,7 +71,7 @@ Intel Core i7-6700K CPU 4.00GHz (Skylake), 1 CPU, 8 logical and 4 physical cores .NET SDK=6.0.100-preview.3.21202.5 [Host] : .NET Core 3.1.18 (CoreCLR 4.700.21.35901, CoreFX 4.700.21.36305), X64 RyuJIT DefaultJob : .NET Core 3.1.18 (CoreCLR 4.700.21.35901, CoreFX 4.700.21.36305), X64 RyuJIT -MASTER + | Method | Mean | Error | StdDev | |------------------------------------ |----------:|----------:|----------:| | 'Baseline 4:4:4 Interleaved' | 12.710 ms | 0.1120 ms | 0.0990 ms | From 582fa51229cc9a8c0a8f600546ea3d9f5acfaa7d Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sun, 21 Nov 2021 05:53:36 +0300 Subject: [PATCH 4/7] Fixed jpeg component mcu size calculation bug --- .../Components/Decoder/HuffmanScanDecoder.cs | 1 + .../Components/Decoder/SpectralConverter.cs | 19 +++++++++++++ .../Decoder/SpectralConverter{TPixel}.cs | 28 ++++++++----------- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs index bc9a53ea04..622657c48f 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs @@ -151,6 +151,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder if (this.componentsCount == this.frame.ComponentCount) { this.ParseBaselineDataInterleaved(); + this.spectralConverter.CommitConvertion(); } else { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs index e975b11fbb..aca9dc36b3 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs @@ -13,6 +13,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// internal abstract class SpectralConverter { + /// + /// Gets a value indicating whether this converter has converted spectral + /// data of the current image or not. + /// + protected bool Converted { get; private set; } + /// /// Injects jpeg image decoding metadata. /// @@ -33,6 +39,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// public abstract void ConvertStrideBaseline(); + /// + /// Marks current converter state as 'converted'. + /// + /// + /// This must be called only for baseline interleaved jpeg's. + /// + public void CommitConvertion() + { + DebugGuard.IsFalse(this.Converted, nameof(this.Converted), $"{nameof(this.CommitConvertion)} must be called only once"); + + this.Converted = true; + } + /// /// Gets the color converter. /// diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs index ec7f3e5c30..2e965e0ac3 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs @@ -3,6 +3,7 @@ using System; using System.Buffers; +using System.Linq; using System.Numerics; using System.Threading; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters; @@ -29,8 +30,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder private Buffer2D pixelBuffer; - private int blockRowsPerStep; - private int pixelRowsPerStep; private int pixelRowCounter; @@ -41,8 +40,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder this.cancellationToken = cancellationToken; } - private bool Converted => this.pixelRowCounter >= this.pixelBuffer.Height; - public Buffer2D GetPixelBuffer() { if (!this.Converted) @@ -52,7 +49,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder for (int step = 0; step < steps; step++) { this.cancellationToken.ThrowIfCancellationRequested(); - this.ConvertNextStride(step); + this.ConvertStride(step); } } @@ -65,18 +62,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder MemoryAllocator allocator = this.configuration.MemoryAllocator; // iteration data - IJpegComponent c0 = frame.Components[0]; + int majorBlockWidth = frame.Components.Max((component) => component.SizeInBlocks.Width); + int majorVerticalSamplingFactor = frame.Components.Max((component) => component.SamplingFactors.Height); const int blockPixelHeight = 8; - this.blockRowsPerStep = c0.SamplingFactors.Height; - this.pixelRowsPerStep = this.blockRowsPerStep * blockPixelHeight; + this.pixelRowsPerStep = majorVerticalSamplingFactor * blockPixelHeight; // pixel buffer for resulting image this.pixelBuffer = allocator.Allocate2D(frame.PixelWidth, frame.PixelHeight); this.paddedProxyPixelRow = allocator.Allocate(frame.PixelWidth + 3); // component processors from spectral to Rgba32 - var postProcessorBufferSize = new Size(c0.SizeInBlocks.Width * 8, this.pixelRowsPerStep); + const int blockPixelWidth = 8; + var postProcessorBufferSize = new Size(majorBlockWidth * blockPixelWidth, this.pixelRowsPerStep); this.componentProcessors = new JpegComponentPostProcessor[frame.Components.Length]; for (int i = 0; i < this.componentProcessors.Length; i++) { @@ -84,7 +82,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } // single 'stride' rgba32 buffer for conversion between spectral and TPixel - // this.rgbaBuffer = allocator.Allocate(frame.PixelWidth); this.rgbBuffer = allocator.Allocate(frame.PixelWidth * 3); // color converter from Rgba32 to TPixel @@ -95,18 +92,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder public override void ConvertStrideBaseline() { // Convert next pixel stride using single spectral `stride' - // Note that zero passing eliminates the need of virtual call from JpegComponentPostProcessor - this.ConvertNextStride(spectralStep: 0); + // Note that zero passing eliminates the need of virtual call + // from JpegComponentPostProcessor + this.ConvertStride(spectralStep: 0); - // Clear spectral stride - this is VERY important as jpeg possibly won't fill entire buffer each stride - // Which leads to decoding artifacts - // Note that this code clears all buffers of the post processors, it's their responsibility to allocate only single stride foreach (JpegComponentPostProcessor cpp in this.componentProcessors) { cpp.ClearSpectralBuffers(); } } + /// public void Dispose() { if (this.componentProcessors != null) @@ -121,7 +117,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder this.paddedProxyPixelRow?.Dispose(); } - private void ConvertNextStride(int spectralStep) + private void ConvertStride(int spectralStep) { int maxY = Math.Min(this.pixelBuffer.Height, this.pixelRowCounter + this.pixelRowsPerStep); From e1c0a39c9d2c8ef712af09f7694068efd0d323bd Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sun, 21 Nov 2021 06:25:31 +0300 Subject: [PATCH 5/7] Added bug proof image to jpeg decoder test suit --- tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs | 2 ++ .../JpegDecoderTests/DecodeBaselineJpeg_jpeg422.png | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 tests/Images/External/ReferenceOutput/JpegDecoderTests/DecodeBaselineJpeg_jpeg422.png diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs index d12240cba3..ef817154d6 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs @@ -20,6 +20,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Baseline.Jpeg420Small, TestImages.Jpeg.Issues.Fuzz.AccessViolationException922, TestImages.Jpeg.Baseline.Jpeg444, + TestImages.Jpeg.Baseline.Jpeg422, TestImages.Jpeg.Baseline.Bad.BadEOF, TestImages.Jpeg.Baseline.MultiScanBaselineCMYK, TestImages.Jpeg.Baseline.YcckSubsample1222, @@ -100,6 +101,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [TestImages.Jpeg.Baseline.Bad.BadEOF] = 0.38f / 100, [TestImages.Jpeg.Baseline.Bad.BadRST] = 0.0589f / 100, + [TestImages.Jpeg.Baseline.Jpeg422] = 0.0013f / 100, [TestImages.Jpeg.Baseline.Testorig420] = 0.38f / 100, [TestImages.Jpeg.Baseline.Jpeg420Small] = 0.287f / 100, [TestImages.Jpeg.Baseline.Turtle420] = 1.0f / 100, diff --git a/tests/Images/External/ReferenceOutput/JpegDecoderTests/DecodeBaselineJpeg_jpeg422.png b/tests/Images/External/ReferenceOutput/JpegDecoderTests/DecodeBaselineJpeg_jpeg422.png new file mode 100644 index 0000000000..018ecda7a5 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/JpegDecoderTests/DecodeBaselineJpeg_jpeg422.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:733cc46271c4402974db2536a55e6ecae3110856df73031ca48dad03745d852d +size 35375 From 5e40977eb033fbc3296561f5ebf30cef2bff7467 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sun, 21 Nov 2021 06:36:57 +0300 Subject: [PATCH 6/7] Fixed typo --- .../Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs | 2 +- .../Formats/Jpeg/Components/Decoder/SpectralConverter.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs index 622657c48f..ad09b50655 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder if (this.componentsCount == this.frame.ComponentCount) { this.ParseBaselineDataInterleaved(); - this.spectralConverter.CommitConvertion(); + this.spectralConverter.CommitConversion(); } else { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs index aca9dc36b3..4e74f62269 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs @@ -45,9 +45,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// /// This must be called only for baseline interleaved jpeg's. /// - public void CommitConvertion() + public void CommitConversion() { - DebugGuard.IsFalse(this.Converted, nameof(this.Converted), $"{nameof(this.CommitConvertion)} must be called only once"); + DebugGuard.IsFalse(this.Converted, nameof(this.Converted), $"{nameof(this.CommitConversion)} must be called only once"); this.Converted = true; } From 2a182d75637702ae8c633545dba1b7fe032bd8b2 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sun, 21 Nov 2021 07:07:03 +0300 Subject: [PATCH 7/7] Updated benchmark results --- tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs index 842eea685a..cb89f90829 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs @@ -74,8 +74,8 @@ Intel Core i7-6700K CPU 4.00GHz (Skylake), 1 CPU, 8 logical and 4 physical cores | Method | Mean | Error | StdDev | |------------------------------------ |----------:|----------:|----------:| -| 'Baseline 4:4:4 Interleaved' | 12.710 ms | 0.1120 ms | 0.0990 ms | -| 'Baseline 4:2:0 Interleaved' | 8.855 ms | 0.1447 ms | 0.1353 ms | -| 'Baseline 4:0:0 (grayscale)' | 1.660 ms | 0.0106 ms | 0.0088 ms | -| 'Progressive 4:2:0 Non-Interleaved' | 14.138 ms | 0.2797 ms | 0.3330 ms | +| 'Baseline 4:4:4 Interleaved' | 11.781 ms | 0.0737 ms | 0.0654 ms | +| 'Baseline 4:2:0 Interleaved' | 8.688 ms | 0.0345 ms | 0.0306 ms | +| 'Baseline 4:0:0 (grayscale)' | 1.643 ms | 0.0092 ms | 0.0086 ms | +| 'Progressive 4:2:0 Non-Interleaved' | 13.770 ms | 0.0928 ms | 0.0823 ms | */