diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
index c4f8a1281f..922e9797cb 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
@@ -248,8 +248,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
///
/// The input stream.
/// Scan decoder used exclusively to decode SOS marker.
- /// The token to monitor cancellation.
- internal void ParseStream(BufferedReadStream stream, HuffmanScanDecoder scanDecoder, CancellationToken ct)
+ /// The token to monitor cancellation.
+ internal void ParseStream(BufferedReadStream stream, HuffmanScanDecoder scanDecoder, CancellationToken cancellationToken)
{
bool metadataOnly = scanDecoder == null;
@@ -283,7 +283,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
while (fileMarker.Marker != JpegConstants.Markers.EOI
|| (fileMarker.Marker == JpegConstants.Markers.EOI && fileMarker.Invalid))
{
- ct.ThrowIfCancellationRequested();
+ cancellationToken.ThrowIfCancellationRequested();
if (!fileMarker.Invalid)
{
@@ -301,7 +301,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
case JpegConstants.Markers.SOS:
if (!metadataOnly)
{
- this.ProcessStartOfScanMarker(stream, ct);
+ this.ProcessStartOfScanMarker(stream, cancellationToken);
break;
}
else
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs
index 6796faa6d0..8659aee634 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs
@@ -1,59 +1,76 @@
-//// 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.IO;
-//using SixLabors.ImageSharp.Tests;
-//using SDSize = System.Drawing.Size;
-
-//namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
-//{
-// [Config(typeof(Config.ShortMultiFramework))]
-// public class DecodeJpegParseStreamOnly
-// {
-// [Params(TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr)]
-// public string TestImage { get; set; }
-
-// private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);
-
-// private byte[] jpegBytes;
-
-// [GlobalSetup]
-// public void Setup()
-// => this.jpegBytes = File.ReadAllBytes(this.TestImageFullPath);
-
-// [Benchmark(Baseline = true, Description = "System.Drawing FULL")]
-// public SDSize JpegSystemDrawing()
-// {
-// using var memoryStream = new MemoryStream(this.jpegBytes);
-// using var image = System.Drawing.Image.FromStream(memoryStream);
-// return image.Size;
-// }
-
-// [Benchmark(Description = "JpegDecoderCore.ParseStream")]
-// public void ParseStream()
-// {
-// using var memoryStream = new MemoryStream(this.jpegBytes);
-// using var bufferedStream = new BufferedReadStream(Configuration.Default, memoryStream);
-
-// var decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder { IgnoreMetadata = true });
-// decoder.ParseStream(bufferedStream);
-// decoder.Dispose();
-// }
-// }
-
-// /*
-// | Method | Job | Runtime | TestImage | Mean | Error | StdDev | Ratio | Gen 0 | Gen 1 | Gen 2 | Allocated |
-// |---------------------------- |----------- |-------------- |--------------------- |---------:|----------:|----------:|------:|--------:|------:|------:|----------:|
-// | 'System.Drawing FULL' | Job-HITJFX | .NET 4.7.2 | Jpg/b(...)e.jpg [21] | 5.828 ms | 0.9885 ms | 0.0542 ms | 1.00 | 46.8750 | - | - | 211566 B |
-// | JpegDecoderCore.ParseStream | Job-HITJFX | .NET 4.7.2 | Jpg/b(...)e.jpg [21] | 5.833 ms | 0.2923 ms | 0.0160 ms | 1.00 | - | - | - | 12416 B |
-// | | | | | | | | | | | | |
-// | 'System.Drawing FULL' | Job-WPSKZD | .NET Core 2.1 | Jpg/b(...)e.jpg [21] | 6.018 ms | 2.1374 ms | 0.1172 ms | 1.00 | 46.8750 | - | - | 210768 B |
-// | JpegDecoderCore.ParseStream | Job-WPSKZD | .NET Core 2.1 | Jpg/b(...)e.jpg [21] | 4.382 ms | 0.9009 ms | 0.0494 ms | 0.73 | - | - | - | 12360 B |
-// | | | | | | | | | | | | |
-// | 'System.Drawing FULL' | Job-ZLSNRP | .NET Core 3.1 | Jpg/b(...)e.jpg [21] | 5.714 ms | 0.4078 ms | 0.0224 ms | 1.00 | - | - | - | 176 B |
-// | JpegDecoderCore.ParseStream | Job-ZLSNRP | .NET Core 3.1 | Jpg/b(...)e.jpg [21] | 4.239 ms | 1.0943 ms | 0.0600 ms | 0.74 | - | - | - | 12406 B |
-// */
-//}
+// 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.Formats.Jpeg.Components.Decoder;
+using SixLabors.ImageSharp.IO;
+using SixLabors.ImageSharp.Tests;
+using SDSize = System.Drawing.Size;
+
+namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
+{
+ //[Config(typeof(Config.ShortMultiFramework))]
+ public class DecodeJpegParseStreamOnly
+ {
+ [Params(TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr)]
+ public string TestImage { get; set; }
+
+ private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);
+
+ private byte[] jpegBytes;
+
+ [GlobalSetup]
+ public void Setup()
+ => this.jpegBytes = File.ReadAllBytes(this.TestImageFullPath);
+
+ //[Benchmark(Baseline = true, Description = "System.Drawing FULL")]
+ //public SDSize JpegSystemDrawing()
+ //{
+ // using var memoryStream = new MemoryStream(this.jpegBytes);
+ // using var image = System.Drawing.Image.FromStream(memoryStream);
+ // return image.Size;
+ //}
+
+ [Benchmark(Description = "JpegDecoderCore.ParseStream")]
+ public void ParseStream()
+ {
+ using var memoryStream = new MemoryStream(this.jpegBytes);
+ using var bufferedStream = new BufferedReadStream(Configuration.Default, memoryStream);
+
+ var decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder { IgnoreMetadata = true });
+ var scanDecoder = new HuffmanScanDecoder(bufferedStream, new NoopSpectralConverter(), cancellationToken: default);
+ decoder.ParseStream(bufferedStream, scanDecoder, cancellationToken: default);
+ decoder.Dispose();
+ }
+
+ // We want to test only stream parsing and scan decoding, we don't need to convert spectral data to actual pixels
+ // Nor we need to allocate final pixel buffer
+ // Note: this still introduces virtual method call overhead for baseline interleaved images
+ // There's no way to eliminate it as spectral conversion is built into the scan decoding loop for memory footprint reduction
+ private class NoopSpectralConverter : SpectralConverter
+ {
+ public override void ConvertStrideBaseline()
+ {
+ }
+
+ public override void InjectFrameData(JpegFrame frame, IRawJpegData jpegData)
+ {
+ }
+ }
+ }
+
+ /*
+ | Method | Job | Runtime | TestImage | Mean | Error | StdDev | Ratio | Gen 0 | Gen 1 | Gen 2 | Allocated |
+ |---------------------------- |----------- |-------------- |--------------------- |---------:|----------:|----------:|------:|--------:|------:|------:|----------:|
+ | 'System.Drawing FULL' | Job-HITJFX | .NET 4.7.2 | Jpg/b(...)e.jpg [21] | 5.828 ms | 0.9885 ms | 0.0542 ms | 1.00 | 46.8750 | - | - | 211566 B |
+ | JpegDecoderCore.ParseStream | Job-HITJFX | .NET 4.7.2 | Jpg/b(...)e.jpg [21] | 5.833 ms | 0.2923 ms | 0.0160 ms | 1.00 | - | - | - | 12416 B |
+ | | | | | | | | | | | | |
+ | 'System.Drawing FULL' | Job-WPSKZD | .NET Core 2.1 | Jpg/b(...)e.jpg [21] | 6.018 ms | 2.1374 ms | 0.1172 ms | 1.00 | 46.8750 | - | - | 210768 B |
+ | JpegDecoderCore.ParseStream | Job-WPSKZD | .NET Core 2.1 | Jpg/b(...)e.jpg [21] | 4.382 ms | 0.9009 ms | 0.0494 ms | 0.73 | - | - | - | 12360 B |
+ | | | | | | | | | | | | |
+ | 'System.Drawing FULL' | Job-ZLSNRP | .NET Core 3.1 | Jpg/b(...)e.jpg [21] | 5.714 ms | 0.4078 ms | 0.0224 ms | 1.00 | - | - | - | 176 B |
+ | JpegDecoderCore.ParseStream | Job-ZLSNRP | .NET Core 3.1 | Jpg/b(...)e.jpg [21] | 4.239 ms | 1.0943 ms | 0.0600 ms | 0.74 | - | - | - | 12406 B |
+ */
+}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs
index 09548e2761..0d4881adab 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs
@@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
var scanDecoder = new HuffmanScanDecoder(bufferedStream, debugConverter, cancellationToken: default);
// This would parse entire image
- decoder.ParseStream(bufferedStream, scanDecoder, ct: default);
+ decoder.ParseStream(bufferedStream, scanDecoder, cancellationToken: default);
// Actual verification
this.VerifySpectralCorrectnessImpl(libJpegData, debugConverter.SpectralData);
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/SpectralToPixelConversionTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/SpectralToPixelConversionTests.cs
index b0e5a3db6b..353ae39f0f 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/SpectralToPixelConversionTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/SpectralToPixelConversionTests.cs
@@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
using var converter = new SpectralConverter(Configuration.Default, cancellationToken: default);
var decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder());
var scanDecoder = new HuffmanScanDecoder(bufferedStream, converter, cancellationToken: default);
- decoder.ParseStream(bufferedStream, scanDecoder, ct: default);
+ decoder.ParseStream(bufferedStream, scanDecoder, cancellationToken: default);
// Test metadata
provider.Utility.TestGroupName = nameof(JpegDecoderTests);