public JpegHuffmanProgressiveScanDecoder(JpegDecoder decoder, JpegFrameHeader frameHeader) : base(decoder)
        {
            _frameHeader = frameHeader;

            // Compute maximum sampling factor
            int maxHorizontalSampling = 1;
            int maxVerticalSampling   = 1;

            foreach (JpegFrameComponentSpecificationParameters currentFrameComponent in frameHeader.Components !)
            {
                maxHorizontalSampling = Math.Max(maxHorizontalSampling, currentFrameComponent.HorizontalSamplingFactor);
                maxVerticalSampling   = Math.Max(maxVerticalSampling, currentFrameComponent.VerticalSamplingFactor);
            }

            _mcusPerLine   = (frameHeader.SamplesPerLine + 8 * maxHorizontalSampling - 1) / (8 * maxHorizontalSampling);
            _mcusPerColumn = (frameHeader.NumberOfLines + 8 * maxVerticalSampling - 1) / (8 * maxVerticalSampling);
            _levelShift    = 1 << (frameHeader.SamplePrecision - 1);

            JpegBlockOutputWriter?outputWriter = decoder.GetOutputWriter();

            if (outputWriter is null)
            {
                ThrowInvalidDataException("Output writer is not set.");
            }
            _outputWriter = outputWriter;
            _allocator    = new JpegBlockAllocator(decoder.MemoryPool);
            _allocator.Allocate(frameHeader);

            // Pre-allocate the JpegDecodeComponent instances
            _components = new JpegHuffmanDecodingComponent[frameHeader.NumberOfComponents];
            for (int i = 0; i < _components.Length; i++)
            {
                _components[i] = new JpegHuffmanDecodingComponent();
            }
        }
        private void DecodeProgressiveDataInterleaved(ref JpegReader reader, JpegScanHeader scanHeader, Span <JpegArithmeticDecodingComponent> components)
        {
            foreach (JpegArithmeticDecodingComponent component in components)
            {
                if (component.DcTable is null || component.DcStatistics is null)
                {
                    ThrowInvalidDataException();
                }
            }

            JpegBlockAllocator allocator = _allocator;
            JpegBitReader      bitReader = new JpegBitReader(reader.RemainingBytes);

            int mcusPerColumn = _mcusPerColumn;
            int mcusPerLine   = _mcusPerLine;

            for (int rowMcu = 0; rowMcu < mcusPerColumn; rowMcu++)
            {
                for (int colMcu = 0; colMcu < mcusPerLine; colMcu++)
                {
                    foreach (JpegArithmeticDecodingComponent component in components)
                    {
                        int index   = component.ComponentIndex;
                        int h       = component.HorizontalSamplingFactor;
                        int v       = component.VerticalSamplingFactor;
                        int offsetX = colMcu * h;
                        int offsetY = rowMcu * v;

                        for (int y = 0; y < v; y++)
                        {
                            int blockOffsetY = offsetY + y;
                            for (int x = 0; x < h; x++)
                            {
                                ref JpegBlock8x8 blockRef = ref allocator.GetBlockReference(index, offsetX + x, blockOffsetY);

                                ReadBlockProgressiveDC(ref bitReader, component, scanHeader, ref blockRef);
                            }
                        }
                    }

                    if (!HandleRestart(ref bitReader, ref reader, ref scanHeader, ref MemoryMarshal.GetReference(components), components.Length))
                    {
                        return;
                    }
                }
            }
        private void DecodeProgressiveDataInterleaved(ref JpegReader reader, JpegScanHeader scanHeader, Span <JpegHuffmanDecodingComponent> components)
        {
            JpegBlockAllocator allocator = _allocator;
            JpegBitReader      bitReader = new JpegBitReader(reader.RemainingBytes);

            int mcusPerColumn = _mcusPerColumn;
            int mcusPerLine   = _mcusPerLine;

            for (int rowMcu = 0; rowMcu < mcusPerColumn; rowMcu++)
            {
                for (int colMcu = 0; colMcu < mcusPerLine; colMcu++)
                {
                    foreach (JpegHuffmanDecodingComponent component in components)
                    {
                        int index   = component.ComponentIndex;
                        int h       = component.HorizontalSamplingFactor;
                        int v       = component.VerticalSamplingFactor;
                        int offsetX = colMcu * h;
                        int offsetY = rowMcu * v;

                        for (int y = 0; y < v; y++)
                        {
                            int blockOffsetY = offsetY + y;
                            for (int x = 0; x < h; x++)
                            {
                                ref JpegBlock8x8 blockRef = ref allocator.GetBlockReference(index, offsetX + x, blockOffsetY);

                                ReadBlockProgressiveDC(ref bitReader, component, scanHeader, ref blockRef);
                            }
                        }
                    }

                    if (!HandleRestart(ref bitReader, ref reader))
                    {
                        return;
                    }
                }
            }