From 639ed629a8594dbba1dc3e11f02985899ad0a9ec Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sun, 11 Jul 2021 12:21:03 +0300 Subject: [PATCH] Implemented new spectral buffers allocation --- .../Jpeg/Components/Decoder/HuffmanScanDecoder.cs | 4 ++++ .../Formats/Jpeg/Components/Decoder/JpegComponent.cs | 12 ++++++++++++ .../Formats/Jpeg/Components/Decoder/JpegFrame.cs | 9 +++++++++ src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs | 3 ++- 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs index 34afa72b43..447f2c6435 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs @@ -128,10 +128,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { if (this.componentsLength == 1) { + this.frame.AllocateComponents(fullScan: true); this.ParseBaselineDataNonInterleaved(); } else { + // interleaved baseline is the only place where we can optimize memory footprint via reusing single spectral stride + this.frame.AllocateComponents(fullScan: false); this.ParseBaselineDataInterleaved(); } } @@ -305,6 +308,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { this.CheckProgressiveData(); + this.frame.AllocateComponents(fullScan: true); if (this.componentsLength == 1) { this.ParseProgressiveDataNonInterleaved(); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs index dd43baa233..05f46aabaa 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs @@ -125,6 +125,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { JpegThrowHelper.ThrowBadSampling(); } + } + + public void AllocateSpectral(bool fullScan) + { + if (this.SpectralBlocks != null) + { + // this method will be called each scan marker so we need to allocate only once + return; + } + + int blocksPerLineForMcu = this.Frame.McusPerLine * this.HorizontalSamplingFactor; + int blocksPerColumnForMcu = fullScan ? this.Frame.McusPerColumn * this.VerticalSamplingFactor : this.VerticalSamplingFactor; int totalNumberOfBlocks = blocksPerColumnForMcu * (blocksPerLineForMcu + 1); int width = this.WidthInBlocks + 1; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs index 13d6bc35ec..595f39dbd3 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs @@ -104,5 +104,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder component.Init(); } } + + public void AllocateComponents(bool fullScan) + { + for (int i = 0; i < this.ComponentCount; i++) + { + JpegComponent component = this.Components[i]; + component.AllocateSpectral(fullScan); + } + } } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 30024af95f..1289ff3bff 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -921,9 +921,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg this.Frame.MaxVerticalFactor = maxV; this.ColorSpace = this.DeduceJpegColorSpace(); this.Metadata.GetJpegMetadata().ColorType = this.ColorSpace == JpegColorSpace.Grayscale ? JpegColorType.Luminance : JpegColorType.YCbCr; - this.Frame.InitComponents(); this.ImageSizeInMCU = new Size(this.Frame.McusPerLine, this.Frame.McusPerColumn); + this.Frame.InitComponents(); + // This can be injected in SOF marker callback this.scanDecoder.InjectFrameData(this.Frame, this); }