// 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 } }
// 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); }
// 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); }
// 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; } } }
// 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 } }
// 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; }
// 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); }