Exemple #1
0
        // 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 arrays. We also generate suitable dummy blocks
        // as needed at the right and lower edges. (The dummy blocks are constructed
        // in the 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_coef() after we've loaded the current strip
        // of the arrays.
        //
        // NB: input_buf contains a plane for each component in image. All
        // components are DCT'd and loaded into the 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).
        static bool compress_first_pass_coef(jpeg_compress cinfo, byte[][][] input_buf)
        {
            jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef;
            c_coef_controller  coef   = (c_coef_controller)lossyc.coef_private;

            uint last_iMCU_row = cinfo.total_iMCU_rows - 1;

            for (int ci = 0; ci < cinfo.num_components; ci++)
            {
                jpeg_component_info compptr = cinfo.comp_info[ci];

                // Align the buffer for this component.
                short[][][] buffer     = coef.whole_image[ci];
                int         buffer_ind = (int)coef.iMCU_row_num * compptr.v_samp_factor;

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

                uint blocks_across = compptr.width_in_blocks;
                int  h_samp_factor = compptr.h_samp_factor;

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

                // 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++)
                {
                    short[][] row = buffer[buffer_ind + block_row];
                    lossyc.fdct_forward_DCT(cinfo, compptr, input_buf[ci], row, 0, (uint)(block_row * DCTSIZE), 0, blocks_across);
                    if (ndummy > 0)
                    {
                        // Create dummy blocks at the right edge of the image.
                        short lastDC = row[blocks_across - 1][0];
                        for (int bi = 0; bi < ndummy; bi++)
                        {
                            short[] block = row[blocks_across + bi];
                            for (int i = 1; i < DCTSIZE2; i++)
                            {
                                block[i] = 0;
                            }
                            block[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 (coef.iMCU_row_num == last_iMCU_row)
                {
                    blocks_across += (uint)ndummy;                   // include lower right corner
                    uint MCUs_across = blocks_across / (uint)h_samp_factor;
                    for (int block_row = block_rows; block_row < compptr.v_samp_factor; block_row++)
                    {
                        short[][] thisblockrow     = buffer[buffer_ind + block_row];
                        short[][] lastblockrow     = buffer[buffer_ind + block_row - 1];
                        int       thisblockrow_ind = 0;
                        int       lastblockrow_ind = h_samp_factor - 1;

                        for (int j = 0; j < blocks_across; j++)
                        {
                            short[] block = thisblockrow[j];
                            for (int i = 0; i < DCTSIZE2; i++)
                            {
                                block[i] = 0;
                            }
                        }

                        for (uint MCUindex = 0; MCUindex < MCUs_across; MCUindex++)
                        {
                            short lastDC = lastblockrow[lastblockrow_ind][0];
                            for (int bi = 0; bi < h_samp_factor; bi++)
                            {
                                thisblockrow[thisblockrow_ind + bi][0] = lastDC;
                            }

                            thisblockrow_ind += h_samp_factor;                           // advance to next MCU in row
                            lastblockrow_ind += 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(compress_output_coef(cinfo, input_buf));
        }
Exemple #2
0
        // Process some data in the single-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.
        // Returns true if the iMCU row is completed, false if suspended.
        //
        // NB: input_buf contains a plane for each component in image,
        // which we index according to the component's SOF position.
        static bool compress_data_coef(jpeg_compress cinfo, byte[][][] input_buf)
        {
            jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef;
            c_coef_controller  coef   = (c_coef_controller)lossyc.coef_private;
            uint last_MCU_col         = cinfo.MCUs_per_row - 1;
            uint last_iMCU_row        = cinfo.total_iMCU_rows - 1;

            // Loop to write as much as one whole iMCU row
            for (int yoffset = coef.MCU_vert_offset; yoffset < coef.MCU_rows_per_iMCU_row; yoffset++)
            {
                for (uint MCU_col_num = coef.mcu_ctr; MCU_col_num <= last_MCU_col; MCU_col_num++)            // index of current MCU within row
                {
                    // Determine where data comes from in input_buf and do the DCT thing.
                    // Each call on forward_DCT processes a horizontal row of DCT blocks
                    // as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks
                    // sequentially. Dummy blocks at the right or bottom edge are filled in
                    // specially. The data in them does not matter for image reconstruction,
                    // so we fill them with values that will encode to the smallest amount of
                    // data, viz: all zeroes in the AC entries, DC entries equal to previous
                    // block's DC value. (Thanks to Thomas Kinsman for this idea.)
                    int blkn = 0;
                    for (int ci = 0; ci < cinfo.comps_in_scan; ci++)
                    {
                        jpeg_component_info compptr = cinfo.cur_comp_info[ci];
                        int blockcnt = (MCU_col_num < last_MCU_col)?compptr.MCU_width:compptr.last_col_width;

                        uint xpos = MCU_col_num * (uint)compptr.MCU_sample_width;
                        uint ypos = (uint)yoffset * DCTSIZE;                     // ypos == (yoffset+yindex) * DCTSIZE

                        for (int yindex = 0; yindex < compptr.MCU_height; yindex++)
                        {
                            if (coef.iMCU_row_num < last_iMCU_row || yoffset + yindex < compptr.last_row_height)
                            {
                                lossyc.fdct_forward_DCT(cinfo, compptr, input_buf[compptr.component_index], coef.MCU_buffer, blkn, ypos, xpos, (uint)blockcnt);
                                if (blockcnt < compptr.MCU_width)
                                {
                                    // Create some dummy blocks at the right edge of the image.
                                    for (int bi = blockcnt; bi < compptr.MCU_width; bi++)
                                    {
                                        short[] block = coef.MCU_buffer[blkn + bi];
                                        for (int i = 1; i < DCTSIZE2; i++)
                                        {
                                            block[i] = 0;                                                               // ACs
                                        }
                                        block[0] = coef.MCU_buffer[blkn + bi - 1][0];                                   // DCs
                                    }
                                }
                            }
                            else
                            {
                                // Create a row of dummy blocks at the bottom of the image.
                                for (int bi = 0; bi < compptr.MCU_width; bi++)
                                {
                                    short[] block = coef.MCU_buffer[blkn + bi];
                                    for (int i = 1; i < DCTSIZE2; i++)
                                    {
                                        block[i] = 0;                                                        // ACs
                                    }
                                    block[0] = coef.MCU_buffer[blkn - 1][0];                                 // DCs
                                }
                            }
                            blkn += compptr.MCU_width;
                            ypos += DCTSIZE;
                        }
                    }

                    // Try to write the MCU. In event of a suspension failure, we will
                    // re-DCT the MCU on restart (a bit inefficient, could be fixed...)
                    if (!lossyc.entropy_encode_mcu(cinfo, coef.MCU_buffer))
                    {
                        // Suspension forced; update state counters and exit
                        coef.MCU_vert_offset = yoffset;
                        coef.mcu_ctr         = MCU_col_num;
                        return(false);
                    }
                }

                // Completed an MCU row, but perhaps not an iMCU row
                coef.mcu_ctr = 0;
            }

            // Completed the iMCU row, advance counters for next one
            coef.iMCU_row_num++;
            start_iMCU_row_c_coef(cinfo);

            return(true);
        }