예제 #1
0
        private bool m_on_odd_row;                                        /* flag to remember which row we are on */

        /// <summary>
        /// Module initialization routine for 1-pass color quantization.
        /// </summary>
        /// <param name="cinfo">The cinfo.</param>
        public My1PassCQuantizer(JpegDecompressStruct cinfo)
        {
            m_cinfo = cinfo;

            m_fserrors[0] = null; /* Flag FS workspace not allocated */
            m_odither[0]  = null; /* Also flag odither arrays not allocated */

            /* Make sure my internal arrays won't overflow */
            if (cinfo.outColorComponents > MAX_Q_COMPS)
            {
                cinfo.ErrExit(JMessageCode.JERR_QUANT_COMPONENTS, MAX_Q_COMPS);
            }

            /* Make sure colormap indexes can be represented by JSAMPLEs */
            if (cinfo.desiredNumberOfColors > (JpegConstants.MAXJSAMPLE + 1))
            {
                cinfo.ErrExit(JMessageCode.JERR_QUANT_MANY_COLORS, JpegConstants.MAXJSAMPLE + 1);
            }

            /* Create the colormap and color index table. */
            CreateColormap();
            CreateColorIndex();

            /* Allocate Floyd-Steinberg workspace now if requested.
             * We do this now since it is FAR storage and may affect the memory
             * manager's space calculations.  If the user changes to FS dither
             * mode in a later pass, we will allocate the space then, and will
             * possibly overrun the max_memory_to_use setting.
             */
            if (cinfo.ditherMode == JDitherMode.JDITHER_FS)
            {
                AllocFsWorkspace();
            }
        }
예제 #2
0
        /// <summary>
        /// Initialize for a processing pass.
        /// </summary>
        public void StartPass(JBufMode pass_mode)
        {
            switch (pass_mode)
            {
            case JBufMode.PassThrough:
                if (m_cinfo.m_upsample.NeedContextRows())
                {
                    m_dataProcessor = DataProcessor.context_main;
                    MakeFunnyPointers(); /* Create the xbuffer[] lists */
                    m_whichFunny    = 0; /* Read first iMCU row into xbuffer[0] */
                    m_context_state = CTX_PREPARE_FOR_IMCU;
                    m_iMCU_row_ctr  = 0;
                }
                else
                {
                    /* Simple case with no context needed */
                    m_dataProcessor = DataProcessor.simple_main;
                }
                m_buffer_full  = false; /* Mark buffer empty */
                m_rowgroup_ctr = 0;
                break;

            case JBufMode.CrankDest:
                /* For last pass of 2-pass quantization, just crank the postprocessor */
                m_dataProcessor = DataProcessor.crank_post;
                break;

            default:
                m_cinfo.ErrExit(JMessageCode.JERR_BAD_BUFFER_MODE);
                break;
            }
        }
예제 #3
0
        /// <summary>
        /// Initialize for a processing pass.
        /// </summary>
        public void StartPass(JBufMode pass_mode)
        {
            switch (pass_mode)
            {
            case JBufMode.PassThrough:
                if (m_cinfo.quantizeColors)
                {
                    /* Single-pass processing with color quantization. */
                    m_processor = ProcessorType.OnePass;

                    /* We could be doing buffered-image output before starting a 2-pass
                     * color quantization; in that case, jinit_d_post_controller did not
                     * allocate a strip buffer.  Use the virtual-array buffer as workspace.
                     */
                    if (m_buffer is null)
                    {
                        m_buffer = m_whole_image.Access(0, m_strip_height);
                    }
                }
                else
                {
                    /* For single-pass processing without color quantization,
                     * I have no work to do; just call the upsampler directly.
                     */
                    m_processor = ProcessorType.Upsample;
                }
                break;

            case JBufMode.SaveAndPass:
                /* First pass of 2-pass quantization */
                if (m_whole_image is null)
                {
                    m_cinfo.ErrExit(JMessageCode.JERR_BAD_BUFFER_MODE);
                }

                m_processor = ProcessorType.PrePass;
                break;

            case JBufMode.CrankDest:
                /* Second pass of 2-pass quantization */
                if (m_whole_image is null)
                {
                    m_cinfo.ErrExit(JMessageCode.JERR_BAD_BUFFER_MODE);
                }

                m_processor = ProcessorType.SecondPass;
                break;

            default:
                m_cinfo.ErrExit(JMessageCode.JERR_BAD_BUFFER_MODE);
                break;
            }

            m_starting_row = m_next_row = 0;
        }
예제 #4
0
        private int m_iMCU_row_ctr;    /* counts iMCU rows to detect image top/bot */

        public JpegDMainController(JpegDecompressStruct cinfo)
        {
            m_cinfo = cinfo;

            /* Allocate the workspace.
             * ngroups is the number of row groups we need.
             */
            var ngroups = cinfo.min_DCT_v_scaled_size;

            if (cinfo.m_upsample.NeedContextRows())
            {
                if (cinfo.min_DCT_v_scaled_size < 2) /* unsupported, see comments above */
                {
                    cinfo.ErrExit(JMessageCode.JERR_NOTIMPL);
                }

                AllocFunnyPointers(); /* Alloc space for xbuffer[] lists */
                ngroups = cinfo.min_DCT_v_scaled_size + 2;
            }

            for (var ci = 0; ci < cinfo.numComponents; ci++)
            {
                /* height of a row group of component */
                var rgroup = (cinfo.CompInfo[ci].V_samp_factor * cinfo.CompInfo[ci].DCT_v_scaled_size) / cinfo.min_DCT_v_scaled_size;

                m_buffer[ci] = JpegCommonStruct.AllocJpegSamples(
                    cinfo.CompInfo[ci].Width_in_blocks * cinfo.CompInfo[ci].DCT_h_scaled_size,
                    rgroup * ngroups);
            }
        }
예제 #5
0
        private void UpSampleComponent(ref ComponentBuffer input_data)
        {
            switch (m_upsampleMethods[m_currentComponent])
            {
            case ComponentUpsampler.noop_upsampler:
                NoOpUpSample();
                break;

            case ComponentUpsampler.fullsize_upsampler:
                FullSizeUpSample(ref input_data);
                break;

            case ComponentUpsampler.h2v1_upsampler:
                H2V1UpSample(ref input_data);
                break;

            case ComponentUpsampler.h2v2_upsampler:
                H2V2UpSample(ref input_data);
                break;

            case ComponentUpsampler.int_upsampler:
                IntUpSample(ref input_data);
                break;

            default:
                m_cinfo.ErrExit(JMessageCode.JERR_NOTIMPL);
                break;
            }
        }
예제 #6
0
        public ReadResult DecompressData(ComponentBuffer[] output_buf)
        {
            switch (m_decompressor)
            {
            case DecompressorType.Ordinary:
                return(DecompressDataOrdinary(output_buf));

            case DecompressorType.Smooth:
                return(DecompressSmoothData(output_buf));

            case DecompressorType.OnePass:
                return(DecompressOnePass(output_buf));
            }

            m_cinfo.ErrExit(JMessageCode.JERR_NOTIMPL);
            return(0);
        }
예제 #7
0
        /// <summary>
        /// <para>Fill the input buffer - called whenever buffer is emptied.</para>
        /// <para>
        /// In typical applications, this should read fresh data into the buffer
        /// (ignoring the current state of next_input_byte and bytes_in_buffer),
        /// reset the pointer and count to the start of the buffer, and return true
        /// indicating that the buffer has been reloaded.  It is not necessary to
        /// fill the buffer entirely, only to obtain at least one more byte.
        /// </para>
        /// <para>
        /// There is no such thing as an EOF return.  If the end of the file has been
        /// reached, the routine has a choice of ERREXIT() or inserting fake data into
        /// the buffer.  In most cases, generating a warning message and inserting a
        /// fake EOI marker is the best course of action --- this will allow the
        /// decompressor to output however much of the image is there.  However,
        /// the resulting error message is misleading if the real problem is an empty
        /// input file, so we handle that case specially.
        /// </para>
        /// <para>
        /// In applications that need to be able to suspend compression due to input
        /// not being available yet, a false return indicates that no more data can be
        /// obtained right now, but more may be forthcoming later.  In this situation,
        /// the decompressor will return to its caller (with an indication of the
        /// number of scanlines it has read, if any).  The application should resume
        /// decompression after it has loaded more data into the input buffer.  Note
        /// that there are substantial restrictions on the use of suspension --- see
        /// the documentation.
        /// </para>
        /// <para>
        /// When suspending, the decompressor will back up to a convenient restart point
        /// (typically the start of the current MCU). next_input_byte and bytes_in_buffer
        /// indicate where the restart point will be if the current call returns false.
        /// Data beyond this point must be rescanned after resumption, so move it to
        /// the front of the buffer rather than discarding it.
        /// </para>
        /// </summary>
        public override bool FillInputBuffer()
        {
            var nbytes = m_infile.Read(m_buffer, 0, INPUT_BUF_SIZE);

            if (nbytes <= 0)
            {
                if (m_start_of_file) /* Treat empty input file as fatal error */
                {
                    m_cinfo.ErrExit(JMessageCode.JERR_INPUT_EMPTY);
                }

                m_cinfo.WarnMS(JMessageCode.JWRN_JPEG_EOF);
                /* Insert a fake EOI marker */
                m_buffer[0] = 0xFF;
                m_buffer[1] = (byte)JpegMarker.EOI;
                nbytes      = 2;
            }

            InitInternalBuffer(m_buffer, nbytes);
            m_start_of_file = false;

            return(true);
        }
예제 #8
0
 public ArithEntropyDecoder(JpegDecompressStruct cinfo)
 {
     cinfo.ErrExit(JMessageCode.JERR_NOTIMPL);
 }
예제 #9
0
        /// <summary>
        /// Per-pass setup.
        /// This is called at the beginning of each output pass.  We determine which
        /// modules will be active during this pass and give them appropriate
        /// start_pass calls.  We also set is_dummy_pass to indicate whether this
        /// is a "real" output pass or a dummy pass for color quantization.
        /// (In the latter case, we will crank the pass to completion.)
        /// </summary>
        public void PrepareForOutputPass()
        {
            if (m_is_dummy_pass)
            {
                /* Final pass of 2-pass quantization */
                m_is_dummy_pass = false;
                m_cinfo.m_cquantize.StartPass(false);
                m_cinfo.m_post.StartPass(JBufMode.CrankDest);
                m_cinfo.m_main.StartPass(JBufMode.CrankDest);
            }
            else
            {
                if (m_cinfo.quantizeColors && m_cinfo.m_colormap is null)
                {
                    /* Select new quantization method */
                    if (m_cinfo.twoPassQuantize && m_cinfo.enable2PassQuant)
                    {
                        m_cinfo.m_cquantize = m_quantizer_2pass;
                        m_is_dummy_pass     = true;
                    }
                    else if (m_cinfo.enable1PassQuant)
                    {
                        m_cinfo.m_cquantize = m_quantizer_1pass;
                    }
                    else
                    {
                        m_cinfo.ErrExit(JMessageCode.JERR_MODE_CHANGE);
                    }
                }

                m_cinfo.m_idct.StartPass();
                m_cinfo.m_coef.StartOutputPass();

                if (!m_cinfo.rawDataOut)
                {
                    m_cinfo.m_upsample.StartPass();

                    if (m_cinfo.quantizeColors)
                    {
                        m_cinfo.m_cquantize.StartPass(m_is_dummy_pass);
                    }

                    m_cinfo.m_post.StartPass(m_is_dummy_pass ? JBufMode.SaveAndPass : JBufMode.PassThrough);
                    m_cinfo.m_main.StartPass(JBufMode.PassThrough);
                }
            }

            /* Set up progress monitor's pass info if present */
            if (m_cinfo.prog is object)
            {
                m_cinfo.prog.CompletedPasses = m_pass_number;
                m_cinfo.prog.TotalPasses     = m_pass_number + (m_is_dummy_pass ? 2 : 1);

                /* In buffered-image mode, we assume one more output pass if EOI not
                 * yet reached, but no more passes if EOI has been reached.
                 */
                if (m_cinfo.bufferedImage && !m_cinfo.m_inputctl.EOIReached())
                {
                    m_cinfo.prog.TotalPasses += (m_cinfo.enable2PassQuant ? 2 : 1);
                }
            }
        }
예제 #10
0
        private int[] rgb_y_tab;        /* => table for RGB to Y conversion */

        /// <summary>
        /// Module initialization routine for output colorspace conversion.
        /// </summary>
        public JpegColorDeconverter(JpegDecompressStruct cinfo)
        {
            m_cinfo = cinfo;

            /* Make sure num_components agrees with jpeg_color_space */
            switch (cinfo.jpegColorSpace)
            {
            case JColorSpace.JCS_GRAYSCALE:
                if (cinfo.numComponents != 1)
                {
                    cinfo.ErrExit(JMessageCode.JERR_BAD_J_COLORSPACE);
                }

                break;

            case JColorSpace.JCS_RGB:
            case JColorSpace.JCS_YCbCr:
            case JColorSpace.JCS_BG_RGB:
            case JColorSpace.JCS_BG_YCC:
                if (cinfo.numComponents != 3)
                {
                    cinfo.ErrExit(JMessageCode.JERR_BAD_J_COLORSPACE);
                }

                break;

            case JColorSpace.JCS_CMYK:
            case JColorSpace.JCS_YCCK:
                if (cinfo.numComponents != 4)
                {
                    cinfo.ErrExit(JMessageCode.JERR_BAD_J_COLORSPACE);
                }

                break;

            case JColorSpace.JCS_NCHANNEL:
                if (cinfo.numComponents < 1)
                {
                    cinfo.ErrExit(JMessageCode.JERR_BAD_J_COLORSPACE);
                }

                break;

            default:
                /* JCS_UNKNOWN can be anything */
                if (cinfo.numComponents < 1)
                {
                    cinfo.ErrExit(JMessageCode.JERR_BAD_J_COLORSPACE);
                }

                break;
            }

            /* Support color transform only for RGB colorspaces */
            if (cinfo.color_transform != JColorTransform.JCT_NONE &&
                cinfo.jpegColorSpace != JColorSpace.JCS_RGB &&
                cinfo.jpegColorSpace != JColorSpace.JCS_BG_RGB)
            {
                cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL);
            }

            /* Set out_color_components and conversion method based on requested space.
             * Also clear the component_needed flags for any unused components,
             * so that earlier pipeline stages can avoid useless computation.
             */

            switch (cinfo.outColorSpace)
            {
            case JColorSpace.JCS_GRAYSCALE:
                cinfo.outColorComponents = 1;
                switch (cinfo.jpegColorSpace)
                {
                case JColorSpace.JCS_GRAYSCALE:
                case JColorSpace.JCS_YCbCr:
                case JColorSpace.JCS_BG_YCC:
                    m_converter = GrayscaleConvert;
                    /* For color->grayscale conversion, only the Y (0) component is needed */
                    for (var ci = 1; ci < cinfo.numComponents; ci++)
                    {
                        cinfo.CompInfo[ci].component_needed = false;
                    }

                    break;

                case JColorSpace.JCS_RGB:
                    switch (cinfo.color_transform)
                    {
                    case JColorTransform.JCT_NONE:
                        m_converter = RgbGrayConvert;
                        break;

                    case JColorTransform.JCT_SUBTRACT_GREEN:
                        m_converter = Rgb1GrayConvert;
                        break;

                    default:
                        cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL);
                        break;
                    }

                    BuildRgbYTable();
                    break;

                default:
                    cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL);
                    break;
                }
                break;

            case JColorSpace.JCS_RGB:
                cinfo.outColorComponents = JpegConstants.RGB_PIXELSIZE;
                switch (cinfo.jpegColorSpace)
                {
                case JColorSpace.JCS_GRAYSCALE:
                    m_converter = GrayRgbConvert;
                    break;

                case JColorSpace.JCS_YCbCr:
                    m_converter = YccRgbConvert;
                    BuildYccRgbTable();
                    break;

                case JColorSpace.JCS_BG_YCC:
                    m_converter = YccRgbConvert;
                    BuildBgYccRgbTable();
                    break;

                case JColorSpace.JCS_RGB:
                    switch (cinfo.color_transform)
                    {
                    case JColorTransform.JCT_NONE:
                        m_converter = RgbConvert;
                        break;

                    case JColorTransform.JCT_SUBTRACT_GREEN:
                        m_converter = Rgb1RgbConvert;
                        break;

                    default:
                        cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL);
                        break;
                    }
                    break;

                case JColorSpace.JCS_CMYK:
                    m_converter = CmykRgbConvert;
                    break;

                case JColorSpace.JCS_YCCK:
                    m_converter = YcckRgbConvert;
                    BuildYccRgbTable();
                    break;

                default:
                    cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL);
                    break;
                }
                break;

            case JColorSpace.JCS_BG_RGB:
                cinfo.outColorComponents = JpegConstants.RGB_PIXELSIZE;
                if (cinfo.jpegColorSpace == JColorSpace.JCS_BG_RGB)
                {
                    switch (cinfo.color_transform)
                    {
                    case JColorTransform.JCT_NONE:
                        m_converter = RgbConvert;
                        break;

                    case JColorTransform.JCT_SUBTRACT_GREEN:
                        m_converter = Rgb1RgbConvert;
                        break;

                    default:
                        cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL);
                        break;
                    }
                }
                else
                {
                    cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL);
                }
                break;

            case JColorSpace.JCS_CMYK:
                cinfo.outColorComponents = 4;
                switch (cinfo.jpegColorSpace)
                {
                case JColorSpace.JCS_YCCK:
                    m_converter = YcckCmykConvert;
                    BuildYccRgbTable();
                    break;

                case JColorSpace.JCS_CMYK:
                    m_converter = NullConvert;
                    break;

                default:
                    cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL);
                    break;
                }
                break;

            case JColorSpace.JCS_NCHANNEL:
                if (cinfo.jpegColorSpace == JColorSpace.JCS_NCHANNEL)
                {
                    m_converter = NullConvert;
                }
                else
                {
                    cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL);
                }

                break;

            default:
                /* Permit null conversion to same output space */
                if (cinfo.outColorSpace == cinfo.jpegColorSpace)
                {
                    cinfo.outColorComponents = cinfo.numComponents;
                    m_converter = NullConvert;
                }
                else
                {
                    /* unsupported non-null conversion */
                    cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL);
                }
                break;
            }

            if (cinfo.quantizeColors)
            {
                cinfo.outputComponents = 1; /* single colormapped output component */
            }
            else
            {
                cinfo.outputComponents = cinfo.outColorComponents;
            }
        }
예제 #11
0
        public MyUpSampler(JpegDecompressStruct cinfo)
        {
            m_cinfo             = cinfo;
            m_need_context_rows = false;  /* until we find out differently */

            if (cinfo.m_CCIR601_sampling) /* this isn't supported */
            {
                cinfo.ErrExit(JMessageCode.JERR_CCIR601_NOTIMPL);
            }

            /* Verify we can handle the sampling factors, select per-component methods,
             * and create storage as needed.
             */
            for (var ci = 0; ci < cinfo.numComponents; ci++)
            {
                var componentInfo = cinfo.CompInfo[ci];

                /* Compute size of an "input group" after IDCT scaling.  This many samples
                 * are to be converted to max_h_samp_factor * max_v_samp_factor pixels.
                 */
                var h_in_group  = (componentInfo.H_samp_factor * componentInfo.DCT_h_scaled_size) / cinfo.min_DCT_h_scaled_size;
                var v_in_group  = (componentInfo.V_samp_factor * componentInfo.DCT_v_scaled_size) / cinfo.min_DCT_v_scaled_size;
                var h_out_group = cinfo.m_max_h_samp_factor;
                var v_out_group = cinfo.m_maxVSampleFactor;

                /* save for use later */
                m_rowgroup_height[ci] = v_in_group;

                if (!componentInfo.component_needed)
                {
                    /* Don't bother to upsample an uninteresting component. */
                    m_upsampleMethods[ci] = ComponentUpsampler.noop_upsampler;
                    continue;           /* don't need to allocate buffer */
                }

                if (h_in_group == h_out_group && v_in_group == v_out_group)
                {
                    /* Fullsize components can be processed without any work. */
                    m_upsampleMethods[ci] = ComponentUpsampler.fullsize_upsampler;
                    continue;           /* don't need to allocate buffer */
                }

                if (h_in_group * 2 == h_out_group && v_in_group == v_out_group)
                {
                    /* Special case for 2h1v upsampling */
                    m_upsampleMethods[ci] = ComponentUpsampler.h2v1_upsampler;
                }
                else if (h_in_group * 2 == h_out_group && v_in_group * 2 == v_out_group)
                {
                    /* Special case for 2h2v upsampling */
                    m_upsampleMethods[ci] = ComponentUpsampler.h2v2_upsampler;
                }
                else if ((h_out_group % h_in_group) == 0 && (v_out_group % v_in_group) == 0)
                {
                    /* Generic integral-factors upsampling method */
                    m_upsampleMethods[ci] = ComponentUpsampler.int_upsampler;
                    m_h_expand[ci]        = (byte)(h_out_group / h_in_group);
                    m_v_expand[ci]        = (byte)(v_out_group / v_in_group);
                }
                else
                {
                    cinfo.ErrExit(JMessageCode.JERR_FRACT_SAMPLE_NOTIMPL);
                }

                var cb = new ComponentBuffer();
                cb.SetBuffer(JpegCommonStruct.AllocJpegSamples(JpegUtils.jround_up(cinfo.outputWidth,
                                                                                   cinfo.m_max_h_samp_factor), cinfo.m_maxVSampleFactor), null, 0);

                m_color_buf[ci] = cb;
            }
        }
예제 #12
0
        /// <summary>
        /// Initialize for one-pass color quantization.
        /// </summary>
        public virtual void StartPass(bool is_pre_scan)
        {
            /* Install my colormap. */
            m_cinfo.m_colormap       = m_sv_colormap;
            m_cinfo.actualColorCount = m_sv_actual;

            /* Initialize for desired dithering mode. */
            switch (m_cinfo.ditherMode)
            {
            case JDitherMode.JDITHER_NONE:
                if (m_cinfo.outColorComponents == 3)
                {
                    m_quantizer = QuantizerType.color_quantizer3;
                }
                else
                {
                    m_quantizer = QuantizerType.color_quantizer;
                }

                break;

            case JDitherMode.JDITHER_ORDERED:
                if (m_cinfo.outColorComponents == 3)
                {
                    m_quantizer = QuantizerType.quantize3_ord_dither_quantizer;
                }
                else
                {
                    m_quantizer = QuantizerType.quantize_ord_dither_quantizer;
                }

                /* initialize state for ordered dither */
                m_row_index = 0;

                /* If user changed to ordered dither from another mode,
                 * we must recreate the color index table with padding.
                 * This will cost extra space, but probably isn't very likely.
                 */
                if (!m_is_padded)
                {
                    CreateColorIndex();
                }

                /* Create ordered-dither tables if we didn't already. */
                if (m_odither[0] is null)
                {
                    CreateODitherTable();
                }

                break;

            case JDitherMode.JDITHER_FS:
                m_quantizer = QuantizerType.quantize_fs_dither_quantizer;

                /* initialize state for F-S dither */
                m_on_odd_row = false;

                /* Allocate Floyd-Steinberg workspace if didn't already. */
                if (m_fserrors[0] is null)
                {
                    AllocFsWorkspace();
                }

                /* Initialize the propagated errors to zero. */
                var arraysize = m_cinfo.outputWidth + 2;
                for (var i = 0; i < m_cinfo.outColorComponents; i++)
                {
                    Array.Clear(m_fserrors[i], 0, arraysize);
                }

                break;

            default:
                m_cinfo.ErrExit(JMessageCode.JERR_NOT_COMPILED);
                break;
            }
        }
예제 #13
0
        /// <summary>
        /// <para>
        /// Read JPEG markers before, between, or after compressed-data scans.
        /// Change state as necessary when a new scan is reached.
        /// Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
        /// </para>
        /// <para>
        /// The consume_input method pointer points either here or to the
        /// coefficient controller's consume_data routine, depending on whether
        /// we are reading a compressed data segment or inter-segment markers.
        /// </para>
        /// <para>
        /// Note: This function should NOT return a pseudo SOS marker(with zero
        /// component number) to the caller.A pseudo marker received by
        /// read_markers is processed and then skipped for other markers.
        /// </para>
        /// </summary>
        private ReadResult ConsumeMarkers()
        {
            ReadResult val;

            if (m_eoi_reached) /* After hitting EOI, read no further */
            {
                return(ReadResult.JPEG_REACHED_EOI);
            }

            /* Loop to pass pseudo SOS marker */
            for (; ;)
            {
                val = m_cinfo.m_marker.ReadMarkers();

                switch (val)
                {
                case ReadResult.JPEG_REACHED_SOS:
                    /* Found SOS */
                    if (m_inheaders != 0)
                    {
                        /* 1st SOS */
                        if (m_inheaders == 1)
                        {
                            InitialSetup();
                        }

                        if (m_cinfo.m_comps_in_scan == 0)
                        {
                            /* pseudo SOS marker */
                            m_inheaders = 2;
                            break;
                        }

                        m_inheaders = 0;

                        /* Note: start_input_pass must be called by jpeg_decomp_master
                         * before any more input can be consumed.
                         */
                    }
                    else
                    {
                        /* 2nd or later SOS marker */
                        if (!m_has_multiple_scans)
                        {
                            /* Oops, I wasn't expecting this! */
                            m_cinfo.ErrExit(JMessageCode.JERR_EOI_EXPECTED);
                        }

                        if (m_cinfo.m_comps_in_scan == 0)
                        {
                            /* unexpected pseudo SOS marker */
                            break;
                        }

                        m_cinfo.m_inputctl.StartInputPass();
                    }
                    return(val);

                case ReadResult.JPEG_REACHED_EOI:
                    /* Found EOI */
                    m_eoi_reached = true;
                    if (m_inheaders != 0)
                    {
                        /* Tables-only datastream, apparently */
                        if (m_cinfo.m_marker.SawSOF())
                        {
                            m_cinfo.ErrExit(JMessageCode.JERR_SOF_NO_SOS);
                        }
                    }
                    else
                    {
                        /* Prevent infinite loop in coef ctlr's decompress_data routine
                         * if user set output_scan_number larger than number of scans.
                         */
                        if (m_cinfo.outputScanNumber > m_cinfo.inputScanNumber)
                        {
                            m_cinfo.outputScanNumber = m_cinfo.inputScanNumber;
                        }
                    }

                    return(val);

                case ReadResult.JPEG_SUSPENDED:
                default:
                    return(val);
                }
            }
        }