// Module initialization routine for Huffman entropy encoding. static void jinit_lhuff_encoder(jpeg_compress cinfo) { jpeg_lossless_c_codec losslsc = (jpeg_lossless_c_codec)cinfo.coef; lhuff_entropy_encoder entropy = null; try { entropy = new lhuff_entropy_encoder(); } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } losslsc.entropy_private = entropy; losslsc.entropy_start_pass = start_pass_huff_ls; losslsc.need_optimization_pass = need_optimization_pass_ls; // Mark tables unallocated for (int i = 0; i < NUM_HUFF_TBLS; i++) { entropy.derived_tbls[i] = null; #if ENTROPY_OPT_SUPPORTED entropy.count_ptrs[i] = null; #endif } }
// Finish up at the end of a Huffman-compressed scan. static void finish_pass_huff_ls(jpeg_compress cinfo) { jpeg_lossless_c_codec losslsc = (jpeg_lossless_c_codec)cinfo.coef; lhuff_entropy_encoder entropy = (lhuff_entropy_encoder)losslsc.entropy_private; // Load up working state ... flush_bits needs it working_state_ls state; 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; 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; }
// Finish up a statistics-gathering pass and create the new Huffman tables. static void finish_pass_gather_ls(jpeg_compress cinfo) { jpeg_lossless_c_codec losslsc = (jpeg_lossless_c_codec)cinfo.coef; lhuff_entropy_encoder entropy = (lhuff_entropy_encoder)losslsc.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]; 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; 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.count_ptrs[dctbl]); did_dc[dctbl] = true; } } }
// 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_ls(jpeg_compress cinfo, bool gather_statistics) { jpeg_lossless_c_codec losslsc = (jpeg_lossless_c_codec)cinfo.coef; lhuff_entropy_encoder entropy = (lhuff_entropy_encoder)losslsc.entropy_private; if (gather_statistics) { #if ENTROPY_OPT_SUPPORTED losslsc.entropy_encode_mcus = encode_mcus_gather_ls; losslsc.entropy_finish_pass = finish_pass_gather_ls; #else ERREXIT(cinfo, J_MESSAGE_CODE.JERR_NOT_COMPILED); #endif } else { losslsc.entropy_encode_mcus = encode_mcus_huff_ls; losslsc.entropy_finish_pass = finish_pass_huff_ls; } 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; 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); } // Allocate and zero the statistics tables // Note that jpeg_gen_optimal_table expects 257 entries in each table! if (entropy.count_ptrs[dctbl] == null) { entropy.count_ptrs[dctbl] = new int[257]; } else { for (int i = 0; i < 257; i++) { entropy.count_ptrs[dctbl][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.derived_tbls[dctbl]); } } // Precalculate encoding info for each sample in an MCU of this scan int ptrn = 0; for (int sampn = 0; sampn < cinfo.block_in_MCU;) { jpeg_component_info compptr = cinfo.cur_comp_info[cinfo.MCU_membership[sampn]]; int ci = compptr.component_index; //ci=cinfo.MCU_membership[sampn]; //compptr=cinfo.cur_comp_info[ci]; for (int yoffset = 0; yoffset < compptr.MCU_height; yoffset++, ptrn++) { // Precalculate the setup info for each input pointer entropy.input_ptr_info[ptrn].ci = ci; entropy.input_ptr_info[ptrn].yoffset = yoffset; entropy.input_ptr_info[ptrn].MCU_width = compptr.MCU_width; for (int xoffset = 0; xoffset < compptr.MCU_width; xoffset++, sampn++) { // Precalculate the input pointer index for each sample entropy.input_ptr_index[sampn] = ptrn; // Precalculate which tables to use for each sample entropy.cur_tbls[sampn] = entropy.derived_tbls[compptr.dc_tbl_no]; entropy.cur_counts[sampn] = entropy.count_ptrs[compptr.dc_tbl_no]; } } } entropy.num_input_ptrs = ptrn; // 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; }
// Huffman coding optimization. // // We first scan the supplied data and count the number of uses of each symbol // that is to be Huffman-coded. (This process MUST agree with the code above.) // Then we build a Huffman coding tree for the observed counts. // Symbols which are not needed at all for the particular image are not // assigned any code, which saves space in the DHT marker as well as in // the compressed data. #if ENTROPY_OPT_SUPPORTED // Trial-encode one nMCU's worth of Huffman-compressed differences. // No data is actually output, so no suspension return is possible. static uint encode_mcus_gather_ls(jpeg_compress cinfo, int[][][] diff_buf, uint MCU_row_num, uint MCU_col_num, uint nMCU) { jpeg_lossless_c_codec losslsc = (jpeg_lossless_c_codec)cinfo.coef; lhuff_entropy_encoder entropy = (lhuff_entropy_encoder)losslsc.entropy_private; // Take care of restart intervals if needed if (cinfo.restart_interval != 0) { if (entropy.restarts_to_go == 0) { entropy.restarts_to_go = cinfo.restart_interval; // Update restart state } entropy.restarts_to_go--; } // Set input pointer locations based on MCU_col_num for (int ptrn = 0; ptrn < entropy.num_input_ptrs; ptrn++) { int ci = entropy.input_ptr_info[ptrn].ci; int yoffset = entropy.input_ptr_info[ptrn].yoffset; int MCU_width = entropy.input_ptr_info[ptrn].MCU_width; entropy.input_ptr[ptrn] = diff_buf[ci][MCU_row_num + yoffset]; entropy.input_ptr_ind[ptrn] = (int)MCU_col_num * MCU_width; } for (uint mcu_num = 0; mcu_num < nMCU; mcu_num++) { // Inner loop handles the samples in the MCU for (int sampn = 0; sampn < cinfo.block_in_MCU; sampn++) { c_derived_tbl dctbl = entropy.cur_tbls[sampn]; int[] counts = entropy.cur_counts[sampn]; // Encode the difference per section H.1.2.2 // Input the sample difference int temp3 = entropy.input_ptr_index[sampn]; int temp = entropy.input_ptr[temp3][entropy.input_ptr_ind[temp3]++]; if ((temp & 0x8000) != 0) { // instead of temp < 0 temp = (-temp) & 0x7FFF; // absolute value, mod 2^16 if (temp == 0) { temp = 0x8000; // special case: magnitude = 32768 } } else { temp &= 0x7FFF; // abs value mod 2^16 } // Find the number of bits needed for the magnitude of the difference int nbits = 0; while (temp != 0) { nbits++; temp >>= 1; } // Check for out-of-range difference values. if (nbits > MAX_DIFF_BITS) { ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_DIFF); } // Count the Huffman symbol for the number of bits counts[nbits]++; } } return(nMCU); }
// Encode and output one nMCU's worth of Huffman-compressed differences. static uint encode_mcus_huff_ls(jpeg_compress cinfo, int[][][] diff_buf, uint MCU_row_num, uint MCU_col_num, uint nMCU) { jpeg_lossless_c_codec losslsc = (jpeg_lossless_c_codec)cinfo.coef; lhuff_entropy_encoder entropy = (lhuff_entropy_encoder)losslsc.entropy_private; // Load up working state working_state_ls state; 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; 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(0); } } } // Set input pointer locations based on MCU_col_num for (int ptrn = 0; ptrn < entropy.num_input_ptrs; ptrn++) { int ci = entropy.input_ptr_info[ptrn].ci; int yoffset = entropy.input_ptr_info[ptrn].yoffset; int MCU_width = entropy.input_ptr_info[ptrn].MCU_width; entropy.input_ptr[ptrn] = diff_buf[ci][MCU_row_num + yoffset]; entropy.input_ptr_ind[ptrn] = (int)MCU_col_num * MCU_width; } for (uint mcu_num = 0; mcu_num < nMCU; mcu_num++) { // Inner loop handles the samples in the MCU for (int sampn = 0; sampn < cinfo.block_in_MCU; sampn++) { c_derived_tbl dctbl = entropy.cur_tbls[sampn]; // Encode the difference per section H.1.2.2 // Input the sample difference int temp3 = entropy.input_ptr_index[sampn]; int temp = entropy.input_ptr[temp3][entropy.input_ptr_ind[temp3]++]; int temp2; if ((temp & 0x8000) != 0) { // instead of temp < 0 temp = (-temp) & 0x7FFF; // absolute value, mod 2^16 if (temp == 0) { temp2 = temp = 0x8000; // special case: magnitude = 32768 } temp2 = ~temp; // one's complement of magnitude } else { temp &= 0x7FFF; // abs value mod 2^16 temp2 = temp; // magnitude } // Find the number of bits needed for the magnitude of the difference int nbits = 0; while (temp != 0) { nbits++; temp >>= 1; } // Check for out-of-range difference values. if (nbits > MAX_DIFF_BITS) { ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_DIFF); } // Emit the Huffman-coded symbol for the number of bits if (!emit_bits(ref state, dctbl.ehufco[nbits], dctbl.ehufsi[nbits])) { return(mcu_num); } // Emit that number of bits of the value, if positive, // or the complement of its magnitude, if negative. if (nbits != 0 && // emit_bits rejects calls with size 0 nbits != 16) // special case: no bits should be emitted { if (!emit_bits(ref state, (uint)temp2, nbits)) { return(mcu_num); } } } // 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; entropy.saved = state.cur; // 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(nMCU); }
// Module initialization routine for Huffman entropy encoding. static void jinit_lhuff_encoder(jpeg_compress cinfo) { jpeg_lossless_c_codec losslsc=(jpeg_lossless_c_codec)cinfo.coef; lhuff_entropy_encoder entropy=null; try { entropy=new lhuff_entropy_encoder(); } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } losslsc.entropy_private=entropy; losslsc.entropy_start_pass=start_pass_huff_ls; losslsc.need_optimization_pass=need_optimization_pass_ls; // Mark tables unallocated for(int i=0; i<NUM_HUFF_TBLS; i++) { entropy.derived_tbls[i]=null; #if ENTROPY_OPT_SUPPORTED entropy.count_ptrs[i]=null; #endif } }