Exemple #1
0
        // Finish up at the end of a Huffman-compressed scan.
        static void finish_pass_huff_sq(jpeg_compress cinfo)
        {
            jpeg_lossy_c_codec    lossyc  = (jpeg_lossy_c_codec)cinfo.coef;
            shuff_entropy_encoder entropy = (shuff_entropy_encoder)lossyc.entropy_private;
            working_state_sq      state;

            state.cur.last_dc_val = new int[MAX_COMPS_IN_SCAN];

            // Load up working state ... flush_bits needs it
            state.output_bytes     = cinfo.dest.output_bytes;
            state.next_output_byte = cinfo.dest.next_output_byte;
            state.free_in_buffer   = cinfo.dest.free_in_buffer;
            state.cur = entropy.saved;
            entropy.saved.last_dc_val.CopyTo(state.cur.last_dc_val, 0);
            state.cinfo = cinfo;

            // Flush out the last data
            if (!flush_bits(ref state))
            {
                ERREXIT(cinfo, J_MESSAGE_CODE.JERR_CANT_SUSPEND);
            }

            // Update state
            cinfo.dest.output_bytes     = state.output_bytes;
            cinfo.dest.next_output_byte = state.next_output_byte;
            cinfo.dest.free_in_buffer   = state.free_in_buffer;
            entropy.saved = state.cur;
            state.cur.last_dc_val.CopyTo(entropy.saved.last_dc_val, 0);
        }
Exemple #2
0
        // Process some data in subsequent passes 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 scan.
        // The data is obtained from the arrays and fed to the entropy coder.
        // Returns true if the iMCU row is completed, false if suspended.
        //
        // NB: input_buf is ignored; it is likely to be a null pointer.
        static bool compress_output_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;

            short[][][][] buffer     = new short[MAX_COMPS_IN_SCAN][][][];
            int[]         buffer_ind = new int[MAX_COMPS_IN_SCAN];

            // Align the buffers for the components used in this scan.
            // NB: during first pass, this is safe only because the buffers will
            // already be aligned properly, so jmemmgr.cs won't need to do any I/O.
            for (int ci = 0; ci < cinfo.comps_in_scan; ci++)
            {
                jpeg_component_info compptr = cinfo.cur_comp_info[ci];
                buffer[ci]     = coef.whole_image[compptr.component_index];
                buffer_ind[ci] = (int)coef.iMCU_row_num * compptr.v_samp_factor;
            }

            // Loop to process 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 < cinfo.MCUs_per_row; MCU_col_num++)
                {
                    // Construct list of pointers to DCT blocks belonging to this MCU
                    int blkn = 0;                   // index of current DCT block within MCU
                    for (int ci = 0; ci < cinfo.comps_in_scan; ci++)
                    {
                        jpeg_component_info compptr = cinfo.cur_comp_info[ci];
                        uint start_col = MCU_col_num * (uint)compptr.MCU_width;
                        for (int yindex = 0; yindex < compptr.MCU_height; yindex++)
                        {
                            short[][] buffer_ptr     = buffer[ci][buffer_ind[ci] + yindex + yoffset];
                            uint      buffer_ptr_ind = start_col;
                            for (int xindex = 0; xindex < compptr.MCU_width; xindex++)
                            {
                                coef.MCU_buffer[blkn++] = buffer_ptr[buffer_ptr_ind++];
                            }
                        }
                    }

                    // Try to write the MCU.
                    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);
        }
Exemple #3
0
        // Initialize for a processing pass.
        static void start_pass_lossy(jpeg_compress cinfo, J_BUF_MODE pass_mode)
        {
            jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef;

            lossyc.fdct_start_pass(cinfo);
            lossyc.coef_start_pass(cinfo, pass_mode);
        }
Exemple #4
0
        // Module initialization routine for Huffman entropy encoding.
        static void jinit_shuff_encoder(jpeg_compress cinfo)
        {
            jpeg_lossy_c_codec    lossyc  = (jpeg_lossy_c_codec)cinfo.coef;
            shuff_entropy_encoder entropy = null;

            try
            {
                entropy = new shuff_entropy_encoder();
                entropy.saved.last_dc_val = new int[MAX_COMPS_IN_SCAN];
            }
            catch
            {
                ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
            }
            lossyc.entropy_private        = entropy;
            lossyc.entropy_start_pass     = start_pass_huff;
            lossyc.need_optimization_pass = need_optimization_pass_sq;

            // Mark tables unallocated
            for (int i = 0; i < NUM_HUFF_TBLS; i++)
            {
                entropy.dc_derived_tbls[i] = entropy.ac_derived_tbls[i] = null;
#if ENTROPY_OPT_SUPPORTED
                entropy.dc_count_ptrs[i] = entropy.ac_count_ptrs[i] = null;
#endif
            }
        }
Exemple #5
0
        // Initialize FDCT manager.
        static void jinit_forward_dct(jpeg_compress cinfo)
        {
            jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef;
            fdct_controller    fdct   = null;

            try
            {
                fdct = new fdct_controller();
            }
            catch
            {
                ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
            }
            lossyc.fdct_private    = fdct;
            lossyc.fdct_start_pass = start_pass_fdctmgr;

            fdct.do_dct             = jpeg_fdct_ifast;
            lossyc.fdct_forward_DCT = forward_DCT;

#if DCT_FLOAT_SUPPORTED
            fdct.do_float_dct = jpeg_fdct_float;
            if (cinfo.useFloatDCT)
            {
                lossyc.fdct_forward_DCT = forward_DCT_float;
            }
#endif
            // Mark divisor tables unallocated
            for (int i = 0; i < NUM_QUANT_TBLS; i++)
            {
                fdct.divisors[i] = null;
#if DCT_FLOAT_SUPPORTED
                fdct.float_divisors[i] = null;
#endif
            }
        }
Exemple #6
0
        // Reset within-iMCU-row counters for a new row
        static void start_iMCU_row_c_coef(jpeg_compress cinfo)
        {
            jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef;
            c_coef_controller  coef   = (c_coef_controller)lossyc.coef_private;

            // In an interleaved scan, an MCU row is the same as an iMCU row.
            // In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
            // But at the bottom of the image, process only what's left.
            if (cinfo.comps_in_scan > 1)
            {
                coef.MCU_rows_per_iMCU_row = 1;
            }
            else
            {
                if (coef.iMCU_row_num < (cinfo.total_iMCU_rows - 1))
                {
                    coef.MCU_rows_per_iMCU_row = cinfo.cur_comp_info[0].v_samp_factor;
                }
                else
                {
                    coef.MCU_rows_per_iMCU_row = cinfo.cur_comp_info[0].last_row_height;
                }
            }

            coef.mcu_ctr         = 0;
            coef.MCU_vert_offset = 0;
        }
Exemple #7
0
        // Trial-encode one MCU's worth of Huffman-compressed coefficients.
        // No data is actually output, so no suspension return is possible.
        static bool encode_mcu_gather_sq(jpeg_compress cinfo, short[][] MCU_data)
        {
            jpeg_lossy_c_codec    lossyc  = (jpeg_lossy_c_codec)cinfo.coef;
            shuff_entropy_encoder entropy = (shuff_entropy_encoder)lossyc.entropy_private;

            // Take care of restart intervals if needed
            if (cinfo.restart_interval != 0)
            {
                if (entropy.restarts_to_go == 0)
                {
                    // Re-initialize DC predictions to 0
                    for (int ci = 0; ci < cinfo.comps_in_scan; ci++)
                    {
                        entropy.saved.last_dc_val[ci] = 0;
                    }
                    // Update restart state
                    entropy.restarts_to_go = cinfo.restart_interval;
                }
                entropy.restarts_to_go--;
            }

            for (int blkn = 0; blkn < cinfo.block_in_MCU; blkn++)
            {
                int ci = cinfo.MCU_membership[blkn];
                jpeg_component_info compptr = cinfo.cur_comp_info[ci];
                htest_one_block_sq(cinfo, MCU_data[blkn], entropy.saved.last_dc_val[ci], entropy.dc_count_ptrs[compptr.dc_tbl_no], entropy.ac_count_ptrs[compptr.ac_tbl_no]);
                entropy.saved.last_dc_val[ci] = MCU_data[blkn][0];
            }

            return(true);
        }
Exemple #8
0
        // Module initialization routine for progressive Huffman entropy encoding.
        static void jinit_phuff_encoder(jpeg_compress cinfo)
        {
            jpeg_lossy_c_codec    lossyc  = (jpeg_lossy_c_codec)cinfo.coef;
            phuff_entropy_encoder entropy = null;

            try
            {
                entropy = new phuff_entropy_encoder();
            }
            catch
            {
                ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
            }

            lossyc.entropy_private        = entropy;
            lossyc.entropy_start_pass     = start_pass_phuff;
            lossyc.need_optimization_pass = need_optimization_pass_phuff;

            // Mark tables unallocated
            for (int i = 0; i < NUM_HUFF_TBLS; i++)
            {
                entropy.derived_tbls[i] = null;
                entropy.count_ptrs[i]   = null;
            }
            entropy.bit_buffer = null;           // needed only in AC refinement scan
        }
Exemple #9
0
        static void jinit_c_coef_controller(jpeg_compress cinfo, bool need_full_buffer)
        {
            jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef;
            c_coef_controller  coef   = null;

            try
            {
                coef = new c_coef_controller();
            }
            catch
            {
                ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
            }

            lossyc.coef_private    = coef;
            lossyc.coef_start_pass = start_pass_coef;

            // Create the coefficient buffer.
            if (need_full_buffer)
            {
#if FULL_COEF_BUFFER_SUPPORTED
                // Allocate a full-image array for each component,
                // padded to a multiple of samp_factor DCT blocks in each direction.
                for (int ci = 0; ci < cinfo.num_components; ci++)
                {
                    jpeg_component_info compptr = cinfo.comp_info[ci];

                    coef.whole_image[ci] = alloc_barray(cinfo,
                                                        (uint)jround_up((int)compptr.width_in_blocks, compptr.h_samp_factor),
                                                        (uint)jround_up((int)compptr.height_in_blocks, compptr.v_samp_factor));
                }
#else
                ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_BUFFER_MODE);
#endif
            }
            else
            {
                // We only need a single-MCU buffer.
                try
                {
                    for (int i = 0; i < C_MAX_BLOCKS_IN_MCU; i++)
                    {
                        coef.MCU_buffer[i] = new short[DCTSIZE2];
                    }
                }
                catch
                {
                    ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
                }

                coef.whole_image[0] = null;               // flag for no arrays
            }
        }
Exemple #10
0
        // Finish up a statistics-gathering pass and create the new Huffman tables.
        static void finish_pass_gather_phuff(jpeg_compress cinfo)
        {
            jpeg_lossy_c_codec    lossyc  = (jpeg_lossy_c_codec)cinfo.coef;
            phuff_entropy_encoder entropy = (phuff_entropy_encoder)lossyc.entropy_private;

            // Flush out buffered data (all we care about is counting the EOB symbol)
            emit_eobrun(entropy);

            bool is_DC_band = (cinfo.Ss == 0);

            // It's important not to apply jpeg_gen_optimal_table more than once
            // per table, because it clobbers the input frequency counts!
            bool[] did = new bool[NUM_HUFF_TBLS];

            for (int ci = 0; ci < cinfo.comps_in_scan; ci++)
            {
                jpeg_component_info compptr = cinfo.cur_comp_info[ci];
                int tbl;
                if (is_DC_band)
                {
                    if (cinfo.Ah != 0)
                    {
                        continue;                                 // DC refinement needs no table
                    }
                    tbl = compptr.dc_tbl_no;
                }
                else
                {
                    tbl = compptr.ac_tbl_no;
                }

                if (!did[tbl])
                {
                    if (is_DC_band)
                    {
                        if (cinfo.dc_huff_tbl_ptrs[tbl] == null)
                        {
                            cinfo.dc_huff_tbl_ptrs[tbl] = jpeg_alloc_huff_table(cinfo);
                        }
                        jpeg_gen_optimal_table(cinfo, cinfo.dc_huff_tbl_ptrs[tbl], entropy.count_ptrs[tbl]);
                    }
                    else
                    {
                        if (cinfo.ac_huff_tbl_ptrs[tbl] == null)
                        {
                            cinfo.ac_huff_tbl_ptrs[tbl] = jpeg_alloc_huff_table(cinfo);
                        }
                        jpeg_gen_optimal_table(cinfo, cinfo.ac_huff_tbl_ptrs[tbl], entropy.count_ptrs[tbl]);
                    }
                    did[tbl] = true;
                }
            }
        }
Exemple #11
0
        // This version is used for floating-point DCT implementations.
        static void forward_DCT_float(jpeg_compress cinfo, jpeg_component_info compptr, byte[][] sample_data, short[][] coef_blocks, int coef_offset, uint start_row, uint start_col, uint num_blocks)
        {
            // This routine is heavily used, so it's worth coding it tightly
            jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef;
            fdct_controller    fdct   = (fdct_controller)lossyc.fdct_private;

            float_DCT_method_ptr do_dct = fdct.do_float_dct;

            double[] divisors  = fdct.float_divisors[compptr.quant_tbl_no];
            double[] workspace = new double[DCTSIZE2];                  // work area for FDCT subroutine

            for (int bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE)
            {
                // Load data into workspace, applying unsigned->signed conversion
                int wsptr = 0;
                for (int elemr = 0; elemr < DCTSIZE; elemr++)
                {
                    byte[] elem = sample_data[start_row + elemr];
                    uint   eptr = start_col;

                    // unroll the inner loop
                    workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE;
                    workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE;
                    workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE;
                    workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE;
                    workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE;
                    workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE;
                    workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE;
                    workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE;
                }

                // Perform the DCT
                do_dct(workspace);

                // Quantize/descale the coefficients, and store into coef_blocks[]
                //old short[] output_ptr=coef_blocks[coef_offset][bi];
                short[] output_ptr = coef_blocks[coef_offset + bi];

                for (int i = 0; i < DCTSIZE2; i++)
                {
                    // Apply the quantization and scaling factor
                    double temp = workspace[i] * divisors[i];

                    // Round to nearest integer.
                    // Since C does not specify the direction of rounding for negative
                    // quotients, we have to force the dividend positive for portability.
                    // The maximum coefficient size is +-16K (for 12-bit data), so this
                    // code should work for either 16-bit or 32-bit ints.
                    output_ptr[i] = (short)((int)(temp + 16384.5) - 16384);
                }
            }
        }
Exemple #12
0
        // MCU encoding for DC successive approximation refinement scan.
        // Note: we assume such scans can be multi-component, although the spec
        // is not very clear on the point.
        static bool encode_mcu_DC_refine_phuff(jpeg_compress cinfo, short[][] MCU_data)
        {
            jpeg_lossy_c_codec    lossyc  = (jpeg_lossy_c_codec)cinfo.coef;
            phuff_entropy_encoder entropy = (phuff_entropy_encoder)lossyc.entropy_private;
            int Al = cinfo.Al;

            entropy.output_bytes     = cinfo.dest.output_bytes;
            entropy.next_output_byte = cinfo.dest.next_output_byte;
            entropy.free_in_buffer   = cinfo.dest.free_in_buffer;

            // Emit restart marker if needed
            if (cinfo.restart_interval != 0)
            {
                if (entropy.restarts_to_go == 0)
                {
                    emit_restart(entropy, entropy.next_restart_num);
                }
            }

            // Encode the MCU data blocks
            for (int blkn = 0; blkn < cinfo.block_in_MCU; blkn++)
            {
                short[] block = MCU_data[blkn];

                // We simply emit the Al'th bit of the DC coefficient value.
                int temp = block[0];
                emit_bits(entropy, (uint)(temp >> Al), 1);
            }

            cinfo.dest.output_bytes     = entropy.output_bytes;
            cinfo.dest.next_output_byte = entropy.next_output_byte;
            cinfo.dest.free_in_buffer   = entropy.free_in_buffer;

            // Update restart-interval state too
            if (cinfo.restart_interval != 0)
            {
                if (entropy.restarts_to_go == 0)
                {
                    entropy.restarts_to_go = cinfo.restart_interval;
                    entropy.next_restart_num++;
                    entropy.next_restart_num &= 7;
                }
                entropy.restarts_to_go--;
            }

            return(true);
        }
Exemple #13
0
        // Finish up at the end of a Huffman-compressed progressive scan.
        static void finish_pass_phuff(jpeg_compress cinfo)
        {
            jpeg_lossy_c_codec    lossyc  = (jpeg_lossy_c_codec)cinfo.coef;
            phuff_entropy_encoder entropy = (phuff_entropy_encoder)lossyc.entropy_private;

            entropy.output_bytes     = cinfo.dest.output_bytes;
            entropy.next_output_byte = cinfo.dest.next_output_byte;
            entropy.free_in_buffer   = cinfo.dest.free_in_buffer;

            // Flush out any buffered data
            emit_eobrun(entropy);
            flush_bits(entropy);

            cinfo.dest.output_bytes     = entropy.output_bytes;
            cinfo.dest.next_output_byte = entropy.next_output_byte;
            cinfo.dest.free_in_buffer   = entropy.free_in_buffer;
        }
Exemple #14
0
        // Initialize for a processing pass.
        static void start_pass_coef(jpeg_compress cinfo, J_BUF_MODE pass_mode)
        {
            jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef;
            c_coef_controller  coef   = (c_coef_controller)lossyc.coef_private;

            coef.iMCU_row_num = 0;
            start_iMCU_row_c_coef(cinfo);

            switch (pass_mode)
            {
            case J_BUF_MODE.JBUF_PASS_THRU:
                if (coef.whole_image[0] != null)
                {
                    ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_BUFFER_MODE);
                }
                lossyc.compress_data = compress_data_coef;
                break;

#if FULL_COEF_BUFFER_SUPPORTED
            case J_BUF_MODE.JBUF_SAVE_AND_PASS:
                if (coef.whole_image[0] == null)
                {
                    ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_BUFFER_MODE);
                }
                lossyc.compress_data = compress_first_pass_coef;
                break;

            case J_BUF_MODE.JBUF_CRANK_DEST:
                if (coef.whole_image[0] == null)
                {
                    ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_BUFFER_MODE);
                }
                lossyc.compress_data = compress_output_coef;
                break;
#endif
            default:
                ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_BUFFER_MODE);
                break;
            }
        }
Exemple #15
0
        // Finish up a statistics-gathering pass and create the new Huffman tables.
        static void finish_pass_gather_sq(jpeg_compress cinfo)
        {
            jpeg_lossy_c_codec    lossyc  = (jpeg_lossy_c_codec)cinfo.coef;
            shuff_entropy_encoder entropy = (shuff_entropy_encoder)lossyc.entropy_private;

            // It's important not to apply jpeg_gen_optimal_table more than once
            // per table, because it clobbers the input frequency counts!
            bool[] did_dc = new bool[NUM_HUFF_TBLS];
            bool[] did_ac = new bool[NUM_HUFF_TBLS];

            for (int ci = 0; ci < cinfo.comps_in_scan; ci++)
            {
                jpeg_component_info compptr = cinfo.cur_comp_info[ci];
                int dctbl = compptr.dc_tbl_no;
                int actbl = compptr.ac_tbl_no;

                if (!did_dc[dctbl])
                {
                    if (cinfo.dc_huff_tbl_ptrs[dctbl] == null)
                    {
                        cinfo.dc_huff_tbl_ptrs[dctbl] = jpeg_alloc_huff_table(cinfo);
                    }
                    jpeg_gen_optimal_table(cinfo, cinfo.dc_huff_tbl_ptrs[dctbl], entropy.dc_count_ptrs[dctbl]);
                    did_dc[dctbl] = true;
                }
                if (!did_ac[actbl])
                {
                    if (cinfo.ac_huff_tbl_ptrs[actbl] == null)
                    {
                        cinfo.ac_huff_tbl_ptrs[actbl] = jpeg_alloc_huff_table(cinfo);
                    }
                    jpeg_gen_optimal_table(cinfo, cinfo.ac_huff_tbl_ptrs[actbl], entropy.ac_count_ptrs[actbl]);
                    did_ac[actbl] = true;
                }
            }
        }
Exemple #16
0
        public static uint jpeg_write_image(jpeg_compress cinfo, byte[] image, bool swapChannels, bool alpha)
        {
            if (cinfo.input_components != 3 || cinfo.lossless || cinfo.in_color_space != J_COLOR_SPACE.JCS_RGB ||
                cinfo.num_components != 3 || cinfo.jpeg_color_space != J_COLOR_SPACE.JCS_YCbCr ||
                cinfo.data_precision != 8 || cinfo.DCT_size != 8 || cinfo.block_in_MCU != 3 || cinfo.arith_code ||
                cinfo.max_h_samp_factor != 1 || cinfo.max_v_samp_factor != 1 || cinfo.next_scanline != 0 || cinfo.num_scans != 1)
            {
                throw new Exception();
            }

            if (cinfo.global_state != STATE.CSCANNING)
            {
                ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_BAD_STATE, cinfo.global_state);
            }

            // Give master control module another chance if this is first call to
            // jpeg_write_scanlines. This lets output of the frame/scan headers be
            // delayed so that application can write COM, etc, markers between
            // jpeg_start_compress and jpeg_write_scanlines.
            if (cinfo.master.call_pass_startup)
            {
                cinfo.master.pass_startup(cinfo);
            }

            jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef;
            c_coef_controller  coef   = (c_coef_controller)lossyc.coef_private;
            fdct_controller    fdct   = (fdct_controller)lossyc.fdct_private;

            double[] workspaceY  = new double[DCTSIZE2];
            double[] workspaceCr = new double[DCTSIZE2];
            double[] workspaceCb = new double[DCTSIZE2];

            short[][] coefs = new short[][] { new short[DCTSIZE2], new short[DCTSIZE2], new short[DCTSIZE2] };

            short[] coefY  = coefs[0];
            short[] coefCb = coefs[1];
            short[] coefCr = coefs[2];

            double[] divisorY = fdct.float_divisors[0];
            double[] divisorC = fdct.float_divisors[1];

            int bpp = alpha?4:3;

            for (int y = 0; y < (cinfo.image_height + DCTSIZE - 1) / DCTSIZE; y++)
            {
                int yFormImage = Math.Min((int)cinfo.image_height - y * DCTSIZE, DCTSIZE);
                for (int x = 0; x < (cinfo.image_width + DCTSIZE - 1) / DCTSIZE; x++)
                {
                    int xFormImage   = Math.Min((int)cinfo.image_width - x * DCTSIZE, DCTSIZE);
                    int workspacepos = 0;
                    for (int j = 0; j < yFormImage; j++)
                    {
                        int imagepos = ((y * DCTSIZE + j) * (int)cinfo.image_width + x * DCTSIZE) * bpp;
                        for (int i = 0; i < xFormImage; i++, workspacepos++)
                        {
                            byte r = image[imagepos++];
                            byte g = image[imagepos++];
                            byte b = image[imagepos++];
                            if (alpha)
                            {
                                imagepos++;
                            }

                            if (!swapChannels)
                            {
                                workspaceY[workspacepos]  = 0.299 * r + 0.587 * g + 0.114 * b - CENTERJSAMPLE;
                                workspaceCb[workspacepos] = -0.168736 * r - 0.331264 * g + 0.5 * b;
                                workspaceCr[workspacepos] = 0.5 * r - 0.418688 * g - 0.081312 * b;
                            }
                            else
                            {
                                workspaceY[workspacepos]  = 0.299 * b + 0.587 * g + 0.114 * r - CENTERJSAMPLE;
                                workspaceCb[workspacepos] = -0.168736 * b - 0.331264 * g + 0.5 * r;
                                workspaceCr[workspacepos] = 0.5 * b - 0.418688 * g - 0.081312 * r;
                            }
                        }

                        int lastworkspacepos = workspacepos - 1;
                        for (int i = xFormImage; i < DCTSIZE; i++, workspacepos++)
                        {
                            workspaceY[workspacepos]  = workspaceY[lastworkspacepos];
                            workspaceCb[workspacepos] = workspaceCb[lastworkspacepos];
                            workspaceCr[workspacepos] = workspaceCr[lastworkspacepos];
                        }
                    }

                    int lastworkspacelinepos = (yFormImage - 1) * DCTSIZE;
                    for (int j = yFormImage; j < DCTSIZE; j++)
                    {
                        int lastworkspacepos = lastworkspacelinepos;
                        for (int i = 0; i < DCTSIZE; i++, workspacepos++, lastworkspacepos++)
                        {
                            workspaceY[workspacepos]  = workspaceY[lastworkspacepos];
                            workspaceCb[workspacepos] = workspaceCb[lastworkspacepos];
                            workspaceCr[workspacepos] = workspaceCr[lastworkspacepos];
                        }
                    }

                    // ein block (3 componenten)
                    jpeg_fdct_float(workspaceY);
                    jpeg_fdct_float(workspaceCb);
                    jpeg_fdct_float(workspaceCr);

                    for (int i = 0; i < DCTSIZE2; i++)
                    {
                        // Apply the quantization and scaling factor
                        double tempY  = workspaceY[i] * divisorY[i];
                        double tempCb = workspaceCb[i] * divisorC[i];
                        double tempCr = workspaceCr[i] * divisorC[i];

                        // Round to nearest integer.
                        // Since C does not specify the direction of rounding for negative
                        // quotients, we have to force the dividend positive for portability.
                        // The maximum coefficient size is +-16K (for 12-bit data), so this
                        // code should work for either 16-bit or 32-bit ints.
                        coefY[i]  = (short)((int)(tempY + 16384.5) - 16384);
                        coefCb[i] = (short)((int)(tempCb + 16384.5) - 16384);
                        coefCr[i] = (short)((int)(tempCr + 16384.5) - 16384);
                    }

                    lossyc.entropy_encode_mcu(cinfo, coefs);
                }
            }

            cinfo.next_scanline = cinfo.image_height;
            return(cinfo.image_height);
        }
Exemple #17
0
        // MCU encoding for AC successive approximation refinement scan.
        static bool encode_mcu_AC_refine_phuff(jpeg_compress cinfo, short[][] MCU_data)
        {
            jpeg_lossy_c_codec    lossyc  = (jpeg_lossy_c_codec)cinfo.coef;
            phuff_entropy_encoder entropy = (phuff_entropy_encoder)lossyc.entropy_private;
            int r;

            byte[] BR_buffer;
            uint   BR;
            int    Se = cinfo.Se;
            int    Al = cinfo.Al;

            int[] absvalues = new int[DCTSIZE2];

            entropy.output_bytes     = cinfo.dest.output_bytes;
            entropy.next_output_byte = cinfo.dest.next_output_byte;
            entropy.free_in_buffer   = cinfo.dest.free_in_buffer;

            // Emit restart marker if needed
            if (cinfo.restart_interval != 0)
            {
                if (entropy.restarts_to_go == 0)
                {
                    emit_restart(entropy, entropy.next_restart_num);
                }
            }

            // Encode the MCU data block
            short[] block = MCU_data[0];

            // It is convenient to make a pre-pass to determine the transformed
            // coefficients' absolute values and the EOB position.
            int EOB = 0;
            int k;

            for (k = cinfo.Ss; k <= Se; k++)
            {
                int temp = block[jpeg_natural_order[k]];
                // We must apply the point transform by Al. For AC coefficients this
                // is an integer division with rounding towards 0. To do this portably
                // in C, we shift after obtaining the absolute value.
                if (temp < 0)
                {
                    temp = -temp;                       // temp is abs value of input
                }
                temp       >>= Al;                      // apply the point transform
                absvalues[k] = temp;                    // save abs value for main pass
                if (temp == 1)
                {
                    EOB = k;                                    // EOB = index of last newly-nonzero coef
                }
            }

            // Encode the AC coefficients per section G.1.2.3, fig. G.7
            r         = 0;                      // r = run length of zeros
            BR        = 0;                      // BR = count of buffered bits added now
            BR_buffer = entropy.bit_buffer;     // Append bits to buffer
            uint BR_buffer_ind = entropy.BE;

            for (k = cinfo.Ss; k <= Se; k++)
            {
                int temp = absvalues[k];
                if (temp == 0)
                {
                    r++;
                    continue;
                }

                // Emit any required ZRLs, but not if they can be folded into EOB
                while (r > 15 && k <= EOB)
                {
                    // emit any pending EOBRUN and the BE correction bits
                    emit_eobrun(entropy);

                    // Emit ZRL
                    emit_symbol(entropy, entropy.ac_tbl_no, 0xF0);
                    r -= 16;

                    // Emit buffered correction bits that must be associated with ZRL
                    emit_buffered_bits(entropy, BR_buffer, BR_buffer_ind, BR);
                    BR_buffer     = entropy.bit_buffer;               // BE bits are gone now
                    BR_buffer_ind = 0;
                    BR            = 0;
                }

                // If the coef was previously nonzero, it only needs a correction bit.
                // NOTE: a straight translation of the spec's figure G.7 would suggest
                // that we also need to test r > 15. But if r > 15, we can only get here
                // if k > EOB, which implies that this coefficient is not 1.
                if (temp > 1)
                {
                    // The correction bit is the next bit of the absolute value.
                    BR_buffer[BR_buffer_ind + BR++] = (byte)(temp & 1);
                    continue;
                }

                // Emit any pending EOBRUN and the BE correction bits
                emit_eobrun(entropy);

                // Count/emit Huffman symbol for run length / number of bits
                emit_symbol(entropy, entropy.ac_tbl_no, (r << 4) + 1);

                // Emit output bit for newly-nonzero coef
                temp = (block[jpeg_natural_order[k]] < 0)?0:1;
                emit_bits(entropy, (uint)temp, 1);

                // Emit buffered correction bits that must be associated with this code
                emit_buffered_bits(entropy, BR_buffer, BR_buffer_ind, BR);
                BR_buffer     = entropy.bit_buffer;           // BE bits are gone now
                BR_buffer_ind = 0;
                BR            = 0;
                r             = 0;   // reset zero run length
            }

            if (r > 0 || BR > 0)      // If there are trailing zeroes,
            {
                entropy.EOBRUN++;     // count an EOB
                entropy.BE += BR;     // concat my correction bits to older ones
                // We force out the EOB if we risk either:
                // 1. overflow of the EOB counter;
                // 2. overflow of the correction bit buffer during the next MCU.
                if (entropy.EOBRUN == 0x7FFF || entropy.BE > (MAX_CORR_BITS - DCTSIZE2 + 1))
                {
                    emit_eobrun(entropy);
                }
            }

            cinfo.dest.output_bytes     = entropy.output_bytes;
            cinfo.dest.next_output_byte = entropy.next_output_byte;
            cinfo.dest.free_in_buffer   = entropy.free_in_buffer;

            // Update restart-interval state too
            if (cinfo.restart_interval != 0)
            {
                if (entropy.restarts_to_go == 0)
                {
                    entropy.restarts_to_go = cinfo.restart_interval;
                    entropy.next_restart_num++;
                    entropy.next_restart_num &= 7;
                }
                entropy.restarts_to_go--;
            }

            return(true);
        }
Exemple #18
0
        const int MAX_CORR_BITS = 1000;         // Max # of correction bits I can buffer

        // Initialize for a Huffman-compressed scan using progressive JPEG.
        static void start_pass_phuff(jpeg_compress cinfo, bool gather_statistics)
        {
            jpeg_lossy_c_codec    lossyc  = (jpeg_lossy_c_codec)cinfo.coef;
            phuff_entropy_encoder entropy = (phuff_entropy_encoder)lossyc.entropy_private;

            entropy.cinfo             = cinfo;
            entropy.gather_statistics = gather_statistics;

            bool is_DC_band = (cinfo.Ss == 0);

            // We assume jcmaster.cs already validated the scan parameters.
            // Select execution routines
            if (cinfo.Ah == 0)
            {
                if (is_DC_band)
                {
                    lossyc.entropy_encode_mcu = encode_mcu_DC_first_phuff;
                }
                else
                {
                    lossyc.entropy_encode_mcu = encode_mcu_AC_first_phuff;
                }
            }
            else
            {
                if (is_DC_band)
                {
                    lossyc.entropy_encode_mcu = encode_mcu_DC_refine_phuff;
                }
                else
                {
                    lossyc.entropy_encode_mcu = encode_mcu_AC_refine_phuff;
                    // AC refinement needs a correction bit buffer
                    if (entropy.bit_buffer == null)
                    {
                        try
                        {
                            entropy.bit_buffer = new byte[MAX_CORR_BITS];
                        }
                        catch
                        {
                            ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
                        }
                    }
                }
            }

            if (gather_statistics)
            {
                lossyc.entropy_finish_pass = finish_pass_gather_phuff;
            }
            else
            {
                lossyc.entropy_finish_pass = finish_pass_phuff;
            }

            // Only DC coefficients may be interleaved, so cinfo.comps_in_scan = 1
            // for AC coefficients.
            for (int ci = 0; ci < cinfo.comps_in_scan; ci++)
            {
                jpeg_component_info compptr = cinfo.cur_comp_info[ci];

                // Initialize DC predictions to 0
                entropy.last_dc_val[ci] = 0;

                // Get table index
                int tbl;
                if (is_DC_band)
                {
                    if (cinfo.Ah != 0)
                    {
                        continue;                                 // DC refinement needs no table
                    }
                    tbl = compptr.dc_tbl_no;
                }
                else
                {
                    entropy.ac_tbl_no = tbl = compptr.ac_tbl_no;
                }

                if (gather_statistics)
                {
                    // Check for invalid table index
                    // (make_c_derived_tbl does this in the other path)
                    if (tbl < 0 || tbl >= NUM_HUFF_TBLS)
                    {
                        ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_NO_HUFF_TABLE, tbl);
                    }

                    // Allocate and zero the statistics tables
                    // Note that jpeg_gen_optimal_table expects 257 entries in each table!
                    if (entropy.count_ptrs[tbl] == null)
                    {
                        try
                        {
                            entropy.count_ptrs[tbl] = new int[257];
                        }
                        catch
                        {
                            ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
                        }
                    }
                    else
                    {
                        for (int i = 0; i < 257; i++)
                        {
                            entropy.count_ptrs[tbl][i] = 0;
                        }
                    }
                }
                else
                {
                    // Compute derived values for Huffman table
                    // We may do this more than once for a table, but it's not expensive
                    jpeg_make_c_derived_tbl(cinfo, is_DC_band, tbl, ref entropy.derived_tbls[tbl]);
                }
            }

            // Initialize AC stuff
            entropy.EOBRUN = 0;
            entropy.BE     = 0;

            // Initialize bit buffer to empty
            entropy.put_buffer = 0;
            entropy.put_bits   = 0;

            // Initialize restart stuff
            entropy.restarts_to_go   = cinfo.restart_interval;
            entropy.next_restart_num = 0;
        }
Exemple #19
0
        // Initialize for a Huffman-compressed scan.
        // If gather_statistics is true, we do not output anything during the scan,
        // just count the Huffman symbols used and generate Huffman code tables.
        static void start_pass_huff(jpeg_compress cinfo, bool gather_statistics)
        {
            jpeg_lossy_c_codec    lossyc  = (jpeg_lossy_c_codec)cinfo.coef;
            shuff_entropy_encoder entropy = (shuff_entropy_encoder)lossyc.entropy_private;

            if (gather_statistics)
            {
#if ENTROPY_OPT_SUPPORTED
                lossyc.entropy_encode_mcu  = encode_mcu_gather_sq;
                lossyc.entropy_finish_pass = finish_pass_gather_sq;
#else
                ERREXIT(cinfo, J_MESSAGE_CODE.JERR_NOT_COMPILED);
#endif
            }
            else
            {
                lossyc.entropy_encode_mcu  = encode_mcu_huff_sq;
                lossyc.entropy_finish_pass = finish_pass_huff_sq;
            }

            for (int ci = 0; ci < cinfo.comps_in_scan; ci++)
            {
                jpeg_component_info compptr = cinfo.cur_comp_info[ci];
                int dctbl = compptr.dc_tbl_no;
                int actbl = compptr.ac_tbl_no;
                if (gather_statistics)
                {
#if ENTROPY_OPT_SUPPORTED
                    // Check for invalid table indexes
                    // (make_c_derived_tbl does this in the other path)
                    if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS)
                    {
                        ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_NO_HUFF_TABLE, dctbl);
                    }
                    if (actbl < 0 || actbl >= NUM_HUFF_TBLS)
                    {
                        ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_NO_HUFF_TABLE, actbl);
                    }

                    // Allocate and zero the statistics tables
                    // Note that jpeg_gen_optimal_table expects 257 entries in each table!
                    if (entropy.dc_count_ptrs[dctbl] == null)
                    {
                        try
                        {
                            entropy.dc_count_ptrs[dctbl] = new int[257];
                        }
                        catch
                        {
                            ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
                        }
                    }
                    else
                    {
                        for (int i = 0; i < 257; i++)
                        {
                            entropy.dc_count_ptrs[dctbl][i] = 0;
                        }
                    }

                    if (entropy.ac_count_ptrs[actbl] == null)
                    {
                        try
                        {
                            entropy.ac_count_ptrs[actbl] = new int[257];
                        }
                        catch
                        {
                            ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
                        }
                    }
                    else
                    {
                        for (int i = 0; i < 257; i++)
                        {
                            entropy.ac_count_ptrs[actbl][i] = 0;
                        }
                    }
#endif
                }
                else
                {
                    // Compute derived values for Huffman tables
                    // We may do this more than once for a table, but it's not expensive
                    jpeg_make_c_derived_tbl(cinfo, true, dctbl, ref entropy.dc_derived_tbls[dctbl]);
                    jpeg_make_c_derived_tbl(cinfo, false, actbl, ref entropy.ac_derived_tbls[actbl]);
                }
                // Initialize DC predictions to 0
                entropy.saved.last_dc_val[ci] = 0;
            }

            // Initialize bit buffer to empty
            entropy.saved.put_buffer = 0;
            entropy.saved.put_bits   = 0;

            // Initialize restart stuff
            entropy.restarts_to_go   = cinfo.restart_interval;
            entropy.next_restart_num = 0;
        }
Exemple #20
0
        // MCU encoding for AC initial scan (either spectral selection,
        // or first pass of successive approximation).
        static bool encode_mcu_AC_first_phuff(jpeg_compress cinfo, short[][] MCU_data)
        {
            jpeg_lossy_c_codec    lossyc  = (jpeg_lossy_c_codec)cinfo.coef;
            phuff_entropy_encoder entropy = (phuff_entropy_encoder)lossyc.entropy_private;
            int Se = cinfo.Se;
            int Al = cinfo.Al;

            entropy.output_bytes     = cinfo.dest.output_bytes;
            entropy.next_output_byte = cinfo.dest.next_output_byte;
            entropy.free_in_buffer   = cinfo.dest.free_in_buffer;

            // Emit restart marker if needed
            if (cinfo.restart_interval != 0)
            {
                if (entropy.restarts_to_go == 0)
                {
                    emit_restart(entropy, entropy.next_restart_num);
                }
            }

            // Encode the MCU data block
            short[] block = MCU_data[0];

            // Encode the AC coefficients per section G.1.2.2, fig. G.3
            int r = 0;           // r = run length of zeros

            for (int k = cinfo.Ss; k <= Se; k++)
            {
                int temp = block[jpeg_natural_order[k]];
                if (temp == 0)
                {
                    r++;
                    continue;
                }

                // We must apply the point transform by Al. For AC coefficients this
                // is an integer division with rounding towards 0. To do this portably
                // in C, we shift after obtaining the absolute value; so the code is
                // interwoven with finding the abs value (temp) and output bits (temp2).
                int temp2;
                if (temp < 0)
                {
                    temp   = -temp;                             // temp is abs value of input
                    temp >>= Al;                                // apply the point transform
                    // For a negative coef, want temp2 = bitwise complement of abs(coef)
                    temp2 = ~temp;
                }
                else
                {
                    temp >>= Al;                                // apply the point transform
                    temp2  = temp;
                }

                // Watch out for case that nonzero coef is zero after point transform
                if (temp == 0)
                {
                    r++;
                    continue;
                }

                // Emit any pending EOBRUN
                if (entropy.EOBRUN > 0)
                {
                    emit_eobrun(entropy);
                }

                // if run length > 15, must emit special run-length-16 codes (0xF0)
                while (r > 15)
                {
                    emit_symbol(entropy, entropy.ac_tbl_no, 0xF0);
                    r -= 16;
                }

                // Find the number of bits needed for the magnitude of the coefficient
                int nbits = 1;               // there must be at least one 1 bit
                while ((temp >>= 1) != 0)
                {
                    nbits++;
                }

                // Check for out-of-range coefficient values
                if (nbits > MAX_COEF_BITS)
                {
                    ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_DCT_COEF);
                }

                // Count/emit Huffman symbol for run length / number of bits
                emit_symbol(entropy, entropy.ac_tbl_no, (r << 4) + nbits);

                // Emit that number of bits of the value, if positive,
                // or the complement of its magnitude, if negative.
                emit_bits(entropy, (uint)temp2, nbits);

                r = 0;               // reset zero run length
            }

            if (r > 0)            // If there are trailing zeroes,
            {
                entropy.EOBRUN++; // count an EOB
                if (entropy.EOBRUN == 0x7FFF)
                {
                    emit_eobrun(entropy);                                        // force it out to avoid overflow
                }
            }

            cinfo.dest.output_bytes     = entropy.output_bytes;
            cinfo.dest.next_output_byte = entropy.next_output_byte;
            cinfo.dest.free_in_buffer   = entropy.free_in_buffer;

            // Update restart-interval state too
            if (cinfo.restart_interval != 0)
            {
                if (entropy.restarts_to_go == 0)
                {
                    entropy.restarts_to_go = cinfo.restart_interval;
                    entropy.next_restart_num++;
                    entropy.next_restart_num &= 7;
                }
                entropy.restarts_to_go--;
            }

            return(true);
        }
Exemple #21
0
        // MCU encoding for DC initial scan (either spectral selection,
        // or first pass of successive approximation).
        static bool encode_mcu_DC_first_phuff(jpeg_compress cinfo, short[][] MCU_data)
        {
            jpeg_lossy_c_codec    lossyc  = (jpeg_lossy_c_codec)cinfo.coef;
            phuff_entropy_encoder entropy = (phuff_entropy_encoder)lossyc.entropy_private;
            int Al = cinfo.Al;

            entropy.output_bytes     = cinfo.dest.output_bytes;
            entropy.next_output_byte = cinfo.dest.next_output_byte;
            entropy.free_in_buffer   = cinfo.dest.free_in_buffer;

            // Emit restart marker if needed
            if (cinfo.restart_interval != 0)
            {
                if (entropy.restarts_to_go == 0)
                {
                    emit_restart(entropy, entropy.next_restart_num);
                }
            }

            // Encode the MCU data blocks
            for (int blkn = 0; blkn < cinfo.block_in_MCU; blkn++)
            {
                short[]             block   = MCU_data[blkn];
                int                 ci      = cinfo.MCU_membership[blkn];
                jpeg_component_info compptr = cinfo.cur_comp_info[ci];

                // Compute the DC value after the required point transform by Al.
                // This is simply an arithmetic right shift.
                int temp2 = (int)block[0] >> Al;

                // DC differences are figured on the point-transformed values.
                int temp = temp2 - entropy.last_dc_val[ci];
                entropy.last_dc_val[ci] = temp2;

                // Encode the DC coefficient difference per section G.1.2.1
                temp2 = temp;
                if (temp < 0)
                {
                    temp = -temp;                   // temp is abs value of input
                    // For a negative input, want temp2 = bitwise complement of abs(input)
                    // This code assumes we are on a two's complement machine
                    temp2--;
                }

                // Find the number of bits needed for the magnitude of the coefficient
                int nbits = 0;
                while (temp != 0)
                {
                    nbits++;
                    temp >>= 1;
                }

                // Check for out-of-range coefficient values.
                // Since we're encoding a difference, the range limit is twice as much.
                if (nbits > MAX_COEF_BITS + 1)
                {
                    ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_DCT_COEF);
                }

                // Count/emit the Huffman-coded symbol for the number of bits
                emit_symbol(entropy, compptr.dc_tbl_no, nbits);

                // Emit that number of bits of the value, if positive,
                // or the complement of its magnitude, if negative.
                if (nbits != 0)
                {
                    emit_bits(entropy, (uint)temp2, nbits);                          // emit_bits rejects calls with size 0
                }
            }

            cinfo.dest.output_bytes     = entropy.output_bytes;
            cinfo.dest.next_output_byte = entropy.next_output_byte;
            cinfo.dest.free_in_buffer   = entropy.free_in_buffer;

            // Update restart-interval state too
            if (cinfo.restart_interval != 0)
            {
                if (entropy.restarts_to_go == 0)
                {
                    entropy.restarts_to_go = cinfo.restart_interval;
                    entropy.next_restart_num++;
                    entropy.next_restart_num &= 7;
                }
                entropy.restarts_to_go--;
            }

            return(true);
        }
Exemple #22
0
        // Perform forward DCT on one or more blocks of a component.
        //
        // The input samples are taken from the sample_data[] array starting at
        // position start_row/start_col, and moving to the right for any additional
        // blocks. The quantized coefficients are returned in coef_blocks[].

        // This version is used for integer DCT implementations.
        static void forward_DCT(jpeg_compress cinfo, jpeg_component_info compptr, byte[][] sample_data, short[][] coef_blocks, int coef_offset, uint start_row, uint start_col, uint num_blocks)
        {
            // This routine is heavily used, so it's worth coding it tightly
            jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef;
            fdct_controller    fdct   = (fdct_controller)lossyc.fdct_private;

            forward_DCT_method_ptr do_dct = fdct.do_dct;

            int[] divisors  = fdct.divisors[compptr.quant_tbl_no];
            int[] workspace = new int[DCTSIZE2];                // work area for FDCT subroutine

            for (int bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE)
            {
                // Load data into workspace, applying unsigned->signed conversion
                int wsptr = 0;
                for (int elemr = 0; elemr < DCTSIZE; elemr++)
                {
                    byte[] elem = sample_data[start_row + elemr];
                    uint   eptr = start_col;

                    // unroll the inner loop
                    workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE;
                    workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE;
                    workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE;
                    workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE;
                    workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE;
                    workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE;
                    workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE;
                    workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE;
                }

                // Perform the DCT
                do_dct(workspace);

                // Quantize/descale the coefficients, and store into coef_blocks[]
                //old short[] output_ptr=coef_blocks[coef_offset][bi];
                short[] output_ptr = coef_blocks[coef_offset + bi];

                for (int i = 0; i < DCTSIZE2; i++)
                {
                    int qval = divisors[i];
                    int temp = workspace[i];
                    // Divide the coefficient value by qval, ensuring proper rounding.
                    // Since C does not specify the direction of rounding for negative
                    // quotients, we have to force the dividend positive for portability.
                    if (temp < 0)
                    {
                        temp  = -temp;
                        temp += qval >> 1;                      // for rounding
                        temp /= qval;
                        temp  = -temp;
                    }
                    else
                    {
                        temp += qval >> 1;                      // for rounding
                        temp /= qval;
                    }
                    output_ptr[i] = (short)temp;
                }
            }
        }
Exemple #23
0
        // Initialize for a processing pass.
        // Verify that all referenced Q-tables are present, and set up
        // the divisor table for each one.
        // In the current implementation, DCT of all components is done during
        // the first pass, even if only some components will be output in the
        // first scan. Hence all components should be examined here.
        static void start_pass_fdctmgr(jpeg_compress cinfo)
        {
            jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef;
            fdct_controller    fdct   = (fdct_controller)lossyc.fdct_private;

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

                // Make sure specified quantization table is present
                if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || cinfo.quant_tbl_ptrs[qtblno] == null)
                {
                    ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_NO_QUANT_TABLE, qtblno);
                }

                JQUANT_TBL qtbl = cinfo.quant_tbl_ptrs[qtblno];

                // Compute divisors for this quant table
                // We may do this more than once for same table, but it's not a big deal
                if (fdct.divisors[qtblno] == null)
                {
                    try
                    {
                        fdct.divisors[qtblno] = new int[DCTSIZE2];
                    }
                    catch
                    {
                        ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
                    }
                }

                int[] dtbl = fdct.divisors[qtblno];
                for (int i = 0; i < DCTSIZE2; i++)
                {
                    dtbl[i] = ((int)qtbl.quantval[i] * aanscales[i] + 1024) >> 11;
                }

#if DCT_FLOAT_SUPPORTED
                if (fdct.float_divisors[qtblno] == null)
                {
                    try
                    {
                        fdct.float_divisors[qtblno] = new double[DCTSIZE2];
                    }
                    catch
                    {
                        ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
                    }
                }

                double[] fdtbl = fdct.float_divisors[qtblno];
                int      di    = 0;
                for (int row = 0; row < DCTSIZE; row++)
                {
                    for (int col = 0; col < DCTSIZE; col++)
                    {
                        fdtbl[di] = 1.0 / (qtbl.quantval[di] * aanscalefactor[row] * aanscalefactor[col] * 8.0);
                        di++;
                    }
                }
#endif
            }
        }
Exemple #24
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 #25
0
        // Initialize the lossy compression codec.
        // This is called only once, during master selection.
        static void jinit_lossy_c_codec(jpeg_compress cinfo)
        {
            jpeg_lossy_c_codec lossyc = null;

            // Create subobject
            try
            {
                if (cinfo.arith_code)
                {
#if C_ARITH_CODING_SUPPORTED
                    lossyc = new arith_entropy_encoder();
#else
                    ERREXIT(cinfo, J_MESSAGE_CODE.JERR_ARITH_NOTIMPL);
#endif
                }
                else
                {
                    lossyc = new jpeg_lossy_c_codec();
                }
            }
            catch
            {
                ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
            }
            cinfo.coef = lossyc;

            // Initialize sub-modules

            // Forward DCT
            jinit_forward_dct(cinfo);

            // Entropy encoding: either Huffman or arithmetic coding.
            if (cinfo.arith_code)
            {
#if C_ARITH_CODING_SUPPORTED
                jinit_arith_encoder(cinfo);
#else
                ERREXIT(cinfo, J_MESSAGE_CODE.JERR_ARITH_NOTIMPL);
#endif
            }
            else
            {
                if (cinfo.process == J_CODEC_PROCESS.JPROC_PROGRESSIVE)
                {
#if C_PROGRESSIVE_SUPPORTED
                    jinit_phuff_encoder(cinfo);
#else
                    ERREXIT(cinfo, J_MESSAGE_CODE.JERR_NOT_COMPILED);
#endif
                }
                else
                {
                    jinit_shuff_encoder(cinfo);
                }
            }

            // Need a full-image coefficient buffer in any multi-pass mode.
            jinit_c_coef_controller(cinfo, cinfo.num_scans > 1 || cinfo.optimize_coding);

            // Initialize method pointers.
            //
            // Note: entropy_start_pass and entropy_finish_pass are assigned in
            // jcshuff.cs, jcphuff.cs or jcarith.cs and compress_data is assigned in jccoefct.cs.
            lossyc.start_pass = start_pass_lossy;
        }
Exemple #26
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);
        }
Exemple #27
0
        // Encode and output one MCU's worth of Huffman-compressed coefficients.
        static bool encode_mcu_huff_sq(jpeg_compress cinfo, short[][] MCU_data)
        {
            jpeg_lossy_c_codec    lossyc  = (jpeg_lossy_c_codec)cinfo.coef;
            shuff_entropy_encoder entropy = (shuff_entropy_encoder)lossyc.entropy_private;

            // Load up working state
            working_state_sq state;

            state.cur.last_dc_val  = new int[MAX_COMPS_IN_SCAN];
            state.output_bytes     = cinfo.dest.output_bytes;
            state.next_output_byte = cinfo.dest.next_output_byte;
            state.free_in_buffer   = cinfo.dest.free_in_buffer;

            //was state.cur=entropy.saved;
            state.cur.put_bits   = entropy.saved.put_bits;
            state.cur.put_buffer = entropy.saved.put_buffer;
            entropy.saved.last_dc_val.CopyTo(state.cur.last_dc_val, 0);

            state.cinfo = cinfo;

            // Emit restart marker if needed
            if (cinfo.restart_interval != 0)
            {
                if (entropy.restarts_to_go == 0)
                {
                    if (!emit_restart(ref state, entropy.next_restart_num))
                    {
                        return(false);
                    }
                }
            }

            // Encode the MCU data blocks
            for (int blkn = 0; blkn < cinfo.block_in_MCU; blkn++)
            {
                int ci = cinfo.MCU_membership[blkn];
                jpeg_component_info compptr = cinfo.cur_comp_info[ci];
                if (!encode_one_block(ref state, MCU_data[blkn], state.cur.last_dc_val[ci], entropy.dc_derived_tbls[compptr.dc_tbl_no], entropy.ac_derived_tbls[compptr.ac_tbl_no]))
                {
                    return(false);
                }

                // Update last_dc_val
                state.cur.last_dc_val[ci] = MCU_data[blkn][0];
            }

            // Completed MCU, so update state
            cinfo.dest.output_bytes     = state.output_bytes;
            cinfo.dest.next_output_byte = state.next_output_byte;
            cinfo.dest.free_in_buffer   = state.free_in_buffer;

            //was entropy.saved=state.cur;
            entropy.saved.put_bits   = state.cur.put_bits;
            entropy.saved.put_buffer = state.cur.put_buffer;
            state.cur.last_dc_val.CopyTo(entropy.saved.last_dc_val, 0);

            // Update restart-interval state too
            if (cinfo.restart_interval != 0)
            {
                if (entropy.restarts_to_go == 0)
                {
                    entropy.restarts_to_go = cinfo.restart_interval;
                    entropy.next_restart_num++;
                    entropy.next_restart_num &= 7;
                }
                entropy.restarts_to_go--;
            }

            return(true);
        }