private JpegScanHeader ProcessScanHeader(ref JpegReader reader, bool metadataOnly)
 {
     if (!reader.TryReadLength(out ushort length))
     {
         ThrowInvalidDataException(reader.ConsumedByteCount, "Unexpected end of input data when reading segment length.");
     }
     if (!reader.TryReadBytes(length, out ReadOnlySequence <byte> buffer))
     {
         ThrowInvalidDataException(reader.ConsumedByteCount, "Unexpected end of input data when reading segment content.");
     }
     if (!JpegScanHeader.TryParse(buffer, metadataOnly, out JpegScanHeader scanHeader, out int bytesConsumed))
     {
         ThrowInvalidDataException(reader.ConsumedByteCount - length + bytesConsumed, "Failed to parse scan header.");
     }
     return(scanHeader);
 }
        public void Optimize(bool strip = true)
        {
            if (_encodingTables.IsEmpty)
            {
                throw new InvalidOperationException();
            }

            IBufferWriter <byte> bufferWriter = _output ?? throw new InvalidOperationException();

            JpegReader reader = new JpegReader(_inputBuffer);
            var        writer = new JpegWriter(bufferWriter, _minimumBufferSegmentSize);

            bool eoiReached               = false;
            bool huffmanTableWritten      = false;
            bool quantizationTableWritten = false;

            while (!eoiReached && !reader.IsEmpty)
            {
                if (!reader.TryReadMarker(out JpegMarker marker))
                {
                    ThrowInvalidDataException(reader.ConsumedByteCount, "No marker found.");
                    return;
                }

                switch (marker)
                {
                case JpegMarker.StartOfImage:
                    writer.WriteMarker(marker);
                    break;

                case JpegMarker.App0:
                case JpegMarker.StartOfFrame0:
                case JpegMarker.StartOfFrame1:
                    writer.WriteMarker(marker);
                    CopyMarkerData(ref reader, ref writer);
                    break;

                case JpegMarker.StartOfFrame2:
                    ProcessFrameHeader(ref reader, false, true);
                    throw new InvalidDataException("Progressive JPEG is not supported currently.");

                case JpegMarker.StartOfFrame3:
                case JpegMarker.StartOfFrame5:
                case JpegMarker.StartOfFrame6:
                case JpegMarker.StartOfFrame7:
                case JpegMarker.StartOfFrame9:
                case JpegMarker.StartOfFrame10:
                case JpegMarker.StartOfFrame11:
                case JpegMarker.StartOfFrame13:
                case JpegMarker.StartOfFrame14:
                case JpegMarker.StartOfFrame15:
                    ThrowInvalidDataException(reader.ConsumedByteCount, $"This type of JPEG stream is not supported ({marker}).");
                    return;

                case JpegMarker.DefineHuffmanTable:
                    if (!huffmanTableWritten)
                    {
                        WriteHuffmanTables(ref writer);
                        huffmanTableWritten = true;
                    }
                    break;

                case JpegMarker.DefineQuantizationTable:
                    if (!quantizationTableWritten)
                    {
                        WriteQuantizationTables(ref writer);
                        quantizationTableWritten = true;
                    }
                    break;

                case JpegMarker.StartOfScan:
                    writer.WriteMarker(marker);
                    ReadOnlySequence <byte> buffer = CopyMarkerData(ref reader, ref writer);
                    if (!JpegScanHeader.TryParse(buffer, false, out JpegScanHeader scanHeader, out _))
                    {
                        ThrowInvalidDataException(reader.ConsumedByteCount - (int)buffer.Length, "Failed to parse scan header.");
                    }
                    CopyScanBaseline(ref reader, ref writer, scanHeader);
                    break;

                case JpegMarker.DefineRestart0:
                case JpegMarker.DefineRestart1:
                case JpegMarker.DefineRestart2:
                case JpegMarker.DefineRestart3:
                case JpegMarker.DefineRestart4:
                case JpegMarker.DefineRestart5:
                case JpegMarker.DefineRestart6:
                case JpegMarker.DefineRestart7:
                    writer.WriteMarker(marker);
                    break;

                case JpegMarker.EndOfImage:
                    writer.WriteMarker(JpegMarker.EndOfImage);
                    eoiReached = true;
                    break;

                default:
                    if (strip)
                    {
                        SkipMarkerData(ref reader);
                    }
                    else
                    {
                        writer.WriteMarker(marker);
                        CopyMarkerData(ref reader, ref writer);
                    }
                    break;
                }
            }

            writer.Flush();
        }