BitMiracle.LibJpeg.Classic.Internal.my_c_coef_controller.compressFirstPass C# (CSharp) Method

compressFirstPass() private method

Process some data in the first pass of a multi-pass case. We process the equivalent of one fully interleaved MCU row ("iMCU" row) per call, ie, v_samp_factor block rows for each component in the image. This amount of data is read from the source buffer, DCT'd and quantized, and saved into the virtual arrays. We also generate suitable dummy blocks as needed at the right and lower edges. (The dummy blocks are constructed in the virtual arrays, which have been padded appropriately.) This makes it possible for subsequent passes not to worry about real vs. dummy blocks. We must also emit the data to the entropy encoder. This is conveniently done by calling compress_output() after we've loaded the current strip of the virtual arrays. NB: input_buf contains a plane for each component in image. All components are DCT'd and loaded into the virtual arrays in this pass. However, it may be that only a subset of the components are emitted to the entropy encoder during this first pass; be careful about looking at the scan-dependent variables (MCU dimensions, etc).
private compressFirstPass ( byte input_buf ) : bool
input_buf byte
return bool
        private bool compressFirstPass(byte[][][] input_buf)
        {
            int last_iMCU_row = m_cinfo.m_total_iMCU_rows - 1;

            for (int ci = 0; ci < m_cinfo.m_num_components; ci++)
            {
                jpeg_component_info componentInfo = m_cinfo.Component_info[ci];

                /* Align the virtual buffer for this component. */
                JBLOCK[][] buffer = m_whole_image[ci].Access(m_iMCU_row_num * componentInfo.V_samp_factor,
                    componentInfo.V_samp_factor);

                /* Count non-dummy DCT block rows in this iMCU row. */
                int block_rows;
                if (m_iMCU_row_num < last_iMCU_row)
                {
                    block_rows = componentInfo.V_samp_factor;
                }
                else
                {
                    /* NB: can't use last_row_height here, since may not be set! */
                    block_rows = componentInfo.height_in_blocks % componentInfo.V_samp_factor;
                    if (block_rows == 0)
                        block_rows = componentInfo.V_samp_factor;
                }

                int blocks_across = componentInfo.Width_in_blocks;
                int h_samp_factor = componentInfo.H_samp_factor;

                /* Count number of dummy blocks to be added at the right margin. */
                int ndummy = blocks_across % h_samp_factor;
                if (ndummy > 0)
                    ndummy = h_samp_factor - ndummy;

                jpeg_forward_dct.forward_DCT_ptr forward_DCT = m_cinfo.m_fdct.forward_DCT[ci];
                /* Perform DCT for all non-dummy blocks in this iMCU row.  Each call
                 * on forward_DCT processes a complete horizontal row of DCT blocks.
                 */
                for (int block_row = 0; block_row < block_rows; block_row++)
                {
                    forward_DCT(componentInfo, input_buf[ci],
                        buffer[block_row], block_row * componentInfo.DCT_v_scaled_size, 0, blocks_across);

                    if (ndummy > 0)
                    {
                        /* Create dummy blocks at the right edge of the image. */
                        Array.Clear(buffer[block_row][blocks_across].data, 0, buffer[block_row][blocks_across].data.Length);

                        short lastDC = buffer[block_row][blocks_across - 1][0];
                        for (int bi = 0; bi < ndummy; bi++)
                            buffer[block_row][blocks_across + bi][0] = lastDC;
                    }
                }

                /* If at end of image, create dummy block rows as needed.
                 * The tricky part here is that within each MCU, we want the DC values
                 * of the dummy blocks to match the last real block's DC value.
                 * This squeezes a few more bytes out of the resulting file...
                 */
                if (m_iMCU_row_num == last_iMCU_row)
                {
                    blocks_across += ndummy;    /* include lower right corner */
                    int MCUs_across = blocks_across / h_samp_factor;
                    for (int block_row = block_rows; block_row < componentInfo.V_samp_factor; block_row++)
                    {
                        for (int i = 0; i < blocks_across; i++)
                            Array.Clear(buffer[block_row][i].data, 0, buffer[block_row][i].data.Length);

                        int thisOffset = 0;
                        int lastOffset = 0;
                        for (int MCUindex = 0; MCUindex < MCUs_across; MCUindex++)
                        {
                            short lastDC = buffer[block_row - 1][lastOffset + h_samp_factor - 1][0];
                            for (int bi = 0; bi < h_samp_factor; bi++)
                                buffer[block_row][thisOffset + bi][0] = lastDC;

                            thisOffset += h_samp_factor; /* advance to next MCU in row */
                            lastOffset += h_samp_factor;
                        }
                    }
                }
            }

            /* NB: compress_output will increment iMCU_row_num if successful.
             * A suspension return will result in redoing all the work above next time.
             */

            /* Emit data to the entropy encoder, sharing code with subsequent passes */
            return compressOutput();
        }