public const int SAVED_COEFS = 6; // we save coef_bits[0..5] // Reset within-iMCU-row counters for a new row (input side) static void start_iMCU_row_d_coef(jpeg_decompress cinfo) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; d_coef_controller coef = (d_coef_controller)lossyd.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 (cinfo.input_iMCU_row < (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; }
// Initialize IDCT manager. static void jinit_inverse_dct(jpeg_decompress cinfo) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; idct_controller idct = null; try { idct = new idct_controller(); } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } lossyd.idct_private = idct; lossyd.idct_start_pass = start_pass_idctmgr; for (int ci = 0; ci < cinfo.num_components; ci++) { jpeg_component_info compptr = cinfo.comp_info[ci]; // Allocate and pre-zero a multiplier table for each component try { compptr.dct_table = new int[DCTSIZE2]; } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } // Mark multiplier table not yet set up for any method idct.cur_method[ci] = -1; } }
// Initialize for an output processing pass. static void start_output_pass_lossy(jpeg_decompress cinfo) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; lossyd.idct_start_pass(cinfo); lossyd.coef_start_output_pass(cinfo); }
// Initialize for a Huffman-compressed scan. static void start_pass_huff_decoder(jpeg_decompress cinfo) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; shuff_entropy_decoder entropy = (shuff_entropy_decoder)lossyd.entropy_private; // Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG. // This ought to be an error condition, but we make it a warning because // there are some baseline files out there with all zeroes in these bytes. if (cinfo.Ss != 0 || cinfo.Se != DCTSIZE2 - 1 || cinfo.Ah != 0 || cinfo.Al != 0) { WARNMS(cinfo, J_MESSAGE_CODE.JWRN_NOT_SEQUENTIAL); } 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; // Compute derived values for Huffman tables // We may do this more than once for a table, but it's not expensive jpeg_make_d_derived_tbl(cinfo, true, dctbl, ref entropy.dc_derived_tbls[dctbl]); jpeg_make_d_derived_tbl(cinfo, false, actbl, ref entropy.ac_derived_tbls[actbl]); // Initialize DC predictions to 0 entropy.saved.last_dc_val[ci] = 0; } // Precalculate decoding info for each block in an MCU of this scan for (int blkn = 0; blkn < cinfo.blocks_in_MCU; blkn++) { int ci = cinfo.MCU_membership[blkn]; jpeg_component_info compptr = cinfo.cur_comp_info[ci]; // Precalculate which table to use for each block entropy.dc_cur_tbls[blkn] = entropy.dc_derived_tbls[compptr.dc_tbl_no]; entropy.ac_cur_tbls[blkn] = entropy.ac_derived_tbls[compptr.ac_tbl_no]; // Decide whether we really care about the coefficient values if (compptr.component_needed) { entropy.dc_needed[blkn] = true; // we don't need the ACs if producing a 1/8th-size image entropy.ac_needed[blkn] = (compptr.DCT_scaled_size > 1); } else { entropy.dc_needed[blkn] = entropy.ac_needed[blkn] = false; } } // Initialize bitread state variables entropy.bitstate.bits_left = 0; entropy.bitstate.get_buffer = 0; // unnecessary, but keeps Purify quiet entropy.insufficient_data = false; // Initialize restart counter entropy.restarts_to_go = cinfo.restart_interval; }
// Initialize for an input processing pass. static void start_input_pass_lossy(jpeg_decompress cinfo) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; latch_quant_tables_lossy(cinfo); lossyd.entropy_start_pass(cinfo); lossyd.coef_start_input_pass(cinfo); }
// Initialize coefficient buffer controller. static void jinit_d_coef_controller(jpeg_decompress cinfo, bool need_full_buffer) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; d_coef_controller coef = null; try { coef = new d_coef_controller(); } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } lossyd.coef_private = coef; lossyd.coef_start_input_pass = start_input_pass_d_coef; lossyd.coef_start_output_pass = start_output_pass_d_coef; #if BLOCK_SMOOTHING_SUPPORTED coef.coef_bits_latch = null; #endif // Create the coefficient buffer. if (need_full_buffer) { #if D_MULTISCAN_FILES_SUPPORTED // Allocate a full-image array for each component, // padded to a multiple of samp_factor DCT blocks in each direction. // Note we ask for a pre-zeroed array. for (int ci = 0; ci < cinfo.num_components; ci++) { jpeg_component_info compptr = cinfo.comp_info[ci]; int access_rows = compptr.v_samp_factor; coef.whole_image[ci] = alloc_barray(cinfo, (uint)jround_up(compptr.width_in_blocks, compptr.h_samp_factor), (uint)jround_up(compptr.height_in_blocks, compptr.v_samp_factor)); } lossyd.consume_data = consume_data; lossyd.decompress_data = decompress_data; lossyd.coef_arrays = coef.whole_image; // link to arrays #else ERREXIT(cinfo, J_MESSAGE_CODE.JERR_NOT_COMPILED); #endif } else { // We only need a single-MCU buffer. for (int i = 0; i < D_MAX_BLOCKS_IN_MCU; i++) { coef.MCU_buffer[i] = new short[DCTSIZE2]; } lossyd.consume_data = dummy_consume_data_d_coef; lossyd.decompress_data = decompress_onepass; lossyd.coef_arrays = null; // flag for no arrays } }
// Module initialization routine for progressive Huffman entropy decoding. public static void jinit_phuff_decoder(jpeg_decompress cinfo) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; phuff_entropy_decoder entropy = null; try { entropy = new phuff_entropy_decoder(); entropy.saved.last_dc_val = new int[MAX_COMPS_IN_SCAN]; } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } lossyd.entropy_private = entropy; lossyd.entropy_start_pass = start_pass_phuff_decoder; // Mark derived tables unallocated for (int i = 0; i < NUM_HUFF_TBLS; i++) { entropy.derived_tbls[i] = null; } try { // Create progression status table cinfo.coef_bits = new int[cinfo.num_components][]; for (int ci = 0; ci < cinfo.num_components; ci++) { int[] coef_bit_ptr = cinfo.coef_bits[ci] = new int[DCTSIZE2]; for (int i = 0; i < DCTSIZE2; i++) { coef_bit_ptr[i] = -1; } } } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } }
// Prepare for an output pass. // Here we select the proper IDCT routine for each component and build // a matching multiplier table. static void start_pass_idctmgr(jpeg_decompress cinfo) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; idct_controller idct = (idct_controller)lossyd.idct_private; for (int ci = 0; ci < cinfo.num_components; ci++) { jpeg_component_info compptr = cinfo.comp_info[ci]; // Select the proper IDCT routine for this component's scaling lossyd.inverse_DCT[ci] = jpeg_idct_ifast; // Create multiplier table from quant table. // However, we can skip this if the component is uninteresting // or if we already built the table. Also, if no quant table // has yet been saved for the component, we leave the // multiplier table all-zero; we'll be reading zeroes from the // coefficient controller's buffer anyway. if (!compptr.component_needed || idct.cur_method[ci] == JDCT_IFAST) { continue; } JQUANT_TBL qtbl = compptr.quant_table; if (qtbl == null) { continue; // happens if no data yet for component } idct.cur_method[ci] = JDCT_IFAST; // For AA&N IDCT method, multipliers are equal to quantization // coefficients scaled by scalefactor[row]*scalefactor[col], where // scalefactor[0] = 1 // scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 // For integer operation, the multiplier table is to be scaled by 2. int[] ifmtbl = compptr.dct_table; for (int i = 0; i < DCTSIZE2; i++) { ifmtbl[i] = (((int)qtbl.quantval[i] * aanscales[i]) + (1 << 11)) >> 12; } } }
// Initialize for an output processing pass. static void start_output_pass_d_coef(jpeg_decompress cinfo) { #if BLOCK_SMOOTHING_SUPPORTED jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; d_coef_controller coef = (d_coef_controller)lossyd.coef_private; // If multipass, check to see whether to use block smoothing on this pass if (lossyd.coef_arrays != null) { if (cinfo.do_block_smoothing && smoothing_ok(cinfo)) { lossyd.decompress_data = decompress_smooth_data; } else { lossyd.decompress_data = decompress_data; } } #endif cinfo.output_iMCU_row = 0; }
//#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x)) // Check for a restart marker & resynchronize decoder. // Returns false if must suspend. static bool process_restart_dphuff(jpeg_decompress cinfo) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; phuff_entropy_decoder entropy = (phuff_entropy_decoder)lossyd.entropy_private; // Throw away any unused bits remaining in bit buffer; // include any full bytes in next_marker's count of discarded bytes cinfo.marker.discarded_bytes += (uint)(entropy.bitstate.bits_left / 8); entropy.bitstate.bits_left = 0; // Advance past the RSTn marker if (!cinfo.marker.read_restart_marker(cinfo)) { return(false); } // Re-initialize DC predictions to 0 for (int ci = 0; ci < cinfo.comps_in_scan; ci++) { entropy.saved.last_dc_val[ci] = 0; } // Re-init EOB run count, too entropy.saved.EOBRUN = 0; // Reset restart counter entropy.restarts_to_go = cinfo.restart_interval; // Reset out-of-data flag, unless read_restart_marker left us smack up // against a marker. In that case we will end up treating the next data // segment as empty, and we can avoid producing bogus output pixels by // leaving the flag set. if (cinfo.unread_marker == 0) { entropy.insufficient_data = false; } return(true); }
// Module initialization routine for Huffman entropy decoding. public static void jinit_shuff_decoder(jpeg_decompress cinfo) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; shuff_entropy_decoder entropy = null; try { entropy = new shuff_entropy_decoder(); entropy.saved.last_dc_val = new int[MAX_COMPS_IN_SCAN]; } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } lossyd.entropy_private = entropy; lossyd.entropy_start_pass = start_pass_huff_decoder; lossyd.entropy_decode_mcu = decode_mcu; // Mark tables unallocated for (int i = 0; i < NUM_HUFF_TBLS; i++) { entropy.dc_derived_tbls[i] = entropy.ac_derived_tbls[i] = null; } }
// MCU decoding for AC initial scan (either spectral selection, // or first pass of successive approximation). static bool decode_mcu_AC_first(jpeg_decompress cinfo, short[][] MCU_data) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; phuff_entropy_decoder entropy = (phuff_entropy_decoder)lossyd.entropy_private; int Se = cinfo.Se; int Al = cinfo.Al; // Process restart marker if needed; may have to suspend if (cinfo.restart_interval != 0) { if (entropy.restarts_to_go == 0) { if (!process_restart_dphuff(cinfo)) { return(false); } } } // If we've run out of data, just leave the MCU set to zeroes. // This way, we return uniform gray for the remainder of the segment. if (!entropy.insufficient_data) { // Load up working state. // We can avoid loading/saving bitread state if in an EOB run. uint EOBRUN = entropy.saved.EOBRUN; // only part of saved state we need // There is always only one block per MCU if (EOBRUN > 0) { EOBRUN--; // if it's a band of zeroes... ...process it now (we do nothing) } else { //was BITREAD_STATE_VARS; bitread_working_state br_state = new bitread_working_state(); //was BITREAD_LOAD_STATE(cinfo, entropy.bitstate); br_state.cinfo = cinfo; br_state.input_bytes = cinfo.src.input_bytes; br_state.next_input_byte = cinfo.src.next_input_byte; br_state.bytes_in_buffer = cinfo.src.bytes_in_buffer; ulong get_buffer = entropy.bitstate.get_buffer; int bits_left = entropy.bitstate.bits_left; short[] block = MCU_data[0]; d_derived_tbl tbl = entropy.ac_derived_tbl; for (int k = cinfo.Ss; k <= Se; k++) { int s = 0, r; //was HUFF_DECODE(s, br_state, tbl, return false, label2); { int nb, look; bool label = false; if (bits_left < HUFF_LOOKAHEAD) { if (!jpeg_fill_bit_buffer(ref br_state, get_buffer, bits_left, 0)) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; if (bits_left < HUFF_LOOKAHEAD) { nb = 1; label = true; if ((s = jpeg_huff_decode(ref br_state, get_buffer, bits_left, tbl, nb)) < 0) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } } if (!label) { //was look=PEEK_BITS(HUFF_LOOKAHEAD); look = ((int)(get_buffer >> (bits_left - HUFF_LOOKAHEAD))) & ((1 << HUFF_LOOKAHEAD) - 1); if ((nb = tbl.look_nbits[look]) != 0) { //was DROP_BITS(nb); bits_left -= nb; s = tbl.look_sym[look]; } else { nb = HUFF_LOOKAHEAD + 1; if ((s = jpeg_huff_decode(ref br_state, get_buffer, bits_left, tbl, nb)) < 0) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } } } r = s >> 4; s &= 15; if (s != 0) { k += r; //was CHECK_BIT_BUFFER(br_state, s, return false); if (bits_left < s) { if (!jpeg_fill_bit_buffer(ref br_state, get_buffer, bits_left, s)) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } //was r = GET_BITS(s); r = ((int)(get_buffer >> (bits_left -= s))) & ((1 << s) - 1); //was s=HUFF_EXTEND(r, s); s = (r < (1 << (s - 1))?r + (((-1) << s) + 1):r); // Scale and output coefficient in natural (dezigzagged) order block[jpeg_natural_order[k]] = (short)(s << Al); } else { if (r == 15) { // ZRL k += 15; // skip 15 zeroes in band } else { // EOBr, run length is 2^r + appended bits EOBRUN = (uint)(1 << r); if (r != 0) { // EOBr, r > 0 //was CHECK_BIT_BUFFER(br_state, r, return false); if (bits_left < r) { if (!jpeg_fill_bit_buffer(ref br_state, get_buffer, bits_left, r)) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } //was r = GET_BITS(r); r = ((int)(get_buffer >> (bits_left -= r))) & ((1 << r) - 1); EOBRUN += (uint)r; } EOBRUN--; // this band is processed at this moment break; // force end-of-band } } } //was BITREAD_SAVE_STATE(cinfo, entropy.bitstate); cinfo.src.input_bytes = br_state.input_bytes; cinfo.src.next_input_byte = br_state.next_input_byte; cinfo.src.bytes_in_buffer = br_state.bytes_in_buffer; entropy.bitstate.get_buffer = get_buffer; entropy.bitstate.bits_left = bits_left; } // Completed MCU, so update state entropy.saved.EOBRUN = EOBRUN; // only part of saved state we need } // Account for restart interval (no-op if not using restarts) entropy.restarts_to_go--; return(true); }
// MCU decoding 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 decode_mcu_DC_refine(jpeg_decompress cinfo, short[][] MCU_data) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; phuff_entropy_decoder entropy = (phuff_entropy_decoder)lossyd.entropy_private; short p1 = (short)(1 << cinfo.Al); // 1 in the bit position being coded // Process restart marker if needed; may have to suspend if (cinfo.restart_interval != 0) { if (entropy.restarts_to_go == 0) { if (!process_restart_dphuff(cinfo)) { return(false); } } } // Not worth the cycles to check insufficient_data here, // since we will not change the data anyway if we read zeroes. // Load up working state //was BITREAD_STATE_VARS; bitread_working_state br_state = new bitread_working_state(); //was BITREAD_LOAD_STATE(cinfo, entropy.bitstate); br_state.cinfo = cinfo; br_state.input_bytes = cinfo.src.input_bytes; br_state.next_input_byte = cinfo.src.next_input_byte; br_state.bytes_in_buffer = cinfo.src.bytes_in_buffer; ulong get_buffer = entropy.bitstate.get_buffer; int bits_left = entropy.bitstate.bits_left; // Outer loop handles each block in the MCU for (int blkn = 0; blkn < cinfo.blocks_in_MCU; blkn++) { short[] block = MCU_data[blkn]; // Encoded data is simply the next bit of the two's-complement DC value //was CHECK_BIT_BUFFER(br_state, 1, return false); if (bits_left < 1) { if (!jpeg_fill_bit_buffer(ref br_state, get_buffer, bits_left, 1)) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } //was if(GET_BITS(1)) if ((((int)(get_buffer >> (bits_left -= 1))) & 1) != 0) { block[0] |= p1; } // Note: since we use |=, repeating the assignment later is safe } // Completed MCU, so update state //was BITREAD_SAVE_STATE(cinfo, entropy.bitstate); cinfo.src.input_bytes = br_state.input_bytes; cinfo.src.next_input_byte = br_state.next_input_byte; cinfo.src.bytes_in_buffer = br_state.bytes_in_buffer; entropy.bitstate.get_buffer = get_buffer; entropy.bitstate.bits_left = bits_left; // Account for restart interval (no-op if not using restarts) entropy.restarts_to_go--; return(true); }
// Initialize the lossy decompression codec. // This is called only once, during master selection. static void jinit_lossy_d_codec(jpeg_decompress cinfo) { jpeg_lossy_d_codec lossyd=null; // Create subobject try { if(cinfo.arith_code) { #if D_ARITH_CODING_SUPPORTED lossyd=new arith_entropy_decoder(); #else ERREXIT(cinfo, J_MESSAGE_CODE.JERR_ARITH_NOTIMPL); #endif } else lossyd=new jpeg_lossy_d_codec(); } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } cinfo.coef=lossyd; // Initialize sub-modules // Inverse DCT jinit_inverse_dct(cinfo); // Entropy decoding: either Huffman or arithmetic coding. if(cinfo.arith_code) { #if D_ARITH_CODING_SUPPORTED jinit_arith_decoder(cinfo); #else ERREXIT(cinfo, J_MESSAGE_CODE.JERR_ARITH_NOTIMPL); #endif } else { if(cinfo.process==J_CODEC_PROCESS.JPROC_PROGRESSIVE) { #if D_PROGRESSIVE_SUPPORTED jinit_phuff_decoder(cinfo); #else ERREXIT(cinfo, J_MESSAGE_CODE.JERR_NOT_COMPILED); #endif } else jinit_shuff_decoder(cinfo); } bool use_c_buffer=cinfo.inputctl.has_multiple_scans||cinfo.buffered_image; jinit_d_coef_controller(cinfo, use_c_buffer); // Initialize method pointers. // // Note: consume_data and decompress_data are assigned in jdcoefct.cs. lossyd.calc_output_dimensions=calc_output_dimensions_lossy; lossyd.start_input_pass=start_input_pass_lossy; lossyd.start_output_pass=start_output_pass_lossy; }
// Initialize the lossy decompression codec. // This is called only once, during master selection. static void jinit_lossy_d_codec(jpeg_decompress cinfo) { jpeg_lossy_d_codec lossyd = null; // Create subobject try { if (cinfo.arith_code) { #if D_ARITH_CODING_SUPPORTED lossyd = new arith_entropy_decoder(); #else ERREXIT(cinfo, J_MESSAGE_CODE.JERR_ARITH_NOTIMPL); #endif } else { lossyd = new jpeg_lossy_d_codec(); } } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } cinfo.coef = lossyd; // Initialize sub-modules // Inverse DCT jinit_inverse_dct(cinfo); // Entropy decoding: either Huffman or arithmetic coding. if (cinfo.arith_code) { #if D_ARITH_CODING_SUPPORTED jinit_arith_decoder(cinfo); #else ERREXIT(cinfo, J_MESSAGE_CODE.JERR_ARITH_NOTIMPL); #endif } else { if (cinfo.process == J_CODEC_PROCESS.JPROC_PROGRESSIVE) { #if D_PROGRESSIVE_SUPPORTED jinit_phuff_decoder(cinfo); #else ERREXIT(cinfo, J_MESSAGE_CODE.JERR_NOT_COMPILED); #endif } else { jinit_shuff_decoder(cinfo); } } bool use_c_buffer = cinfo.inputctl.has_multiple_scans || cinfo.buffered_image; jinit_d_coef_controller(cinfo, use_c_buffer); // Initialize method pointers. // // Note: consume_data and decompress_data are assigned in jdcoefct.cs. lossyd.calc_output_dimensions = calc_output_dimensions_lossy; lossyd.start_input_pass = start_input_pass_lossy; lossyd.start_output_pass = start_output_pass_lossy; }
// MCU decoding for AC successive approximation refinement scan. static bool decode_mcu_AC_refine(jpeg_decompress cinfo, short[][] MCU_data) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; phuff_entropy_decoder entropy = (phuff_entropy_decoder)lossyd.entropy_private; int Se = cinfo.Se; short p1 = (short)(1 << cinfo.Al); // 1 in the bit position being coded short m1 = (short)((-1) << cinfo.Al); // -1 in the bit position being coded short[] block = null; // If we are forced to suspend, we must undo the assignments to any newly // nonzero coefficients in the block, because otherwise we'd get confused // next time about which coefficients were already nonzero. // But we need not undo addition of bits to already-nonzero coefficients; // instead, we can test the current bit to see if we already did it. int num_newnz = 0; int[] newnz_pos = new int[DCTSIZE2]; // Process restart marker if needed; may have to suspend if (cinfo.restart_interval != 0) { if (entropy.restarts_to_go == 0) { if (!process_restart_dphuff(cinfo)) { return(false); } } } // If we've run out of data, don't modify the MCU. if (!entropy.insufficient_data) { // Load up working state //was BITREAD_STATE_VARS; bitread_working_state br_state = new bitread_working_state(); //was BITREAD_LOAD_STATE(cinfo, entropy.bitstate); br_state.cinfo = cinfo; br_state.input_bytes = cinfo.src.input_bytes; br_state.next_input_byte = cinfo.src.next_input_byte; br_state.bytes_in_buffer = cinfo.src.bytes_in_buffer; ulong get_buffer = entropy.bitstate.get_buffer; int bits_left = entropy.bitstate.bits_left; uint EOBRUN = entropy.saved.EOBRUN; // only part of saved state we need // There is always only one block per MCU block = MCU_data[0]; d_derived_tbl tbl = entropy.ac_derived_tbl; // initialize coefficient loop counter to start of band int k = cinfo.Ss; if (EOBRUN == 0) { for (; k <= Se; k++) { int s = 0, r; //was HUFF_DECODE(s, br_state, tbl, goto undoit, label3); { int nb, look; bool label = false; if (bits_left < HUFF_LOOKAHEAD) { if (!jpeg_fill_bit_buffer(ref br_state, get_buffer, bits_left, 0)) { goto undoit; } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; if (bits_left < HUFF_LOOKAHEAD) { nb = 1; label = true; if ((s = jpeg_huff_decode(ref br_state, get_buffer, bits_left, tbl, nb)) < 0) { goto undoit; } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } } if (!label) { //was look=PEEK_BITS(HUFF_LOOKAHEAD); look = ((int)(get_buffer >> (bits_left - HUFF_LOOKAHEAD))) & ((1 << HUFF_LOOKAHEAD) - 1); if ((nb = tbl.look_nbits[look]) != 0) { //was DROP_BITS(nb); bits_left -= nb; s = tbl.look_sym[look]; } else { nb = HUFF_LOOKAHEAD + 1; if ((s = jpeg_huff_decode(ref br_state, get_buffer, bits_left, tbl, nb)) < 0) { goto undoit; } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } } } r = s >> 4; s &= 15; if (s != 0) { if (s != 1) { WARNMS(cinfo, J_MESSAGE_CODE.JWRN_HUFF_BAD_CODE); // size of new coef should always be 1 } //was CHECK_BIT_BUFFER(br_state, 1, goto undoit); if (bits_left < 1) { if (!jpeg_fill_bit_buffer(ref br_state, get_buffer, bits_left, 1)) { goto undoit; } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } //was if (GET_BITS(1)) if ((((int)(get_buffer >> (bits_left -= 1))) & 1) != 0) { s = p1; // newly nonzero coef is positive } else { s = m1; // newly nonzero coef is negative } } else { if (r != 15) { EOBRUN = (uint)(1 << r); // EOBr, run length is 2^r + appended bits if (r != 0) { //was CHECK_BIT_BUFFER(br_state, r, goto undoit); if (bits_left < r) { if (!jpeg_fill_bit_buffer(ref br_state, get_buffer, bits_left, r)) { goto undoit; } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } //was r = GET_BITS(r); r = ((int)(get_buffer >> (bits_left -= r))) & ((1 << r) - 1); EOBRUN += (uint)r; } break; // rest of block is handled by EOB logic } // note s = 0 for processing ZRL } // Advance over already-nonzero coefs and r still-zero coefs, // appending correction bits to the nonzeroes. A correction bit is 1 // if the absolute value of the coefficient must be increased. do { int thiscoef = jpeg_natural_order[k]; if (block[thiscoef] != 0) { //was CHECK_BIT_BUFFER(br_state, 1, goto undoit); if (bits_left < 1) { if (!jpeg_fill_bit_buffer(ref br_state, get_buffer, bits_left, 1)) { goto undoit; } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } //was if (GET_BITS(1)) if ((((int)(get_buffer >> (bits_left -= 1))) & 1) != 0) { if ((block[thiscoef] & p1) == 0) { // do nothing if already set it if (block[thiscoef] >= 0) { block[thiscoef] += p1; } else { block[thiscoef] += m1; } } } } else { if (--r < 0) { break; // reached target zero coefficient } } k++; } while(k <= Se); if (s != 0) { int pos = jpeg_natural_order[k]; // Output newly nonzero coefficient block[pos] = (short)s; // Remember its position in case we have to suspend newnz_pos[num_newnz++] = pos; } } } if (EOBRUN > 0) { // Scan any remaining coefficient positions after the end-of-band // (the last newly nonzero coefficient, if any). Append a correction // bit to each already-nonzero coefficient. A correction bit is 1 // if the absolute value of the coefficient must be increased. for (; k <= Se; k++) { int thiscoef = jpeg_natural_order[k]; if (block[thiscoef] != 0) { //was CHECK_BIT_BUFFER(br_state, 1, goto undoit); if (bits_left < 1) { if (!jpeg_fill_bit_buffer(ref br_state, get_buffer, bits_left, 1)) { goto undoit; } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } //was if (GET_BITS(1)) if ((((int)(get_buffer >> (bits_left -= 1))) & 1) != 0) { if ((block[thiscoef] & p1) == 0) { // do nothing if already changed it if (block[thiscoef] >= 0) { block[thiscoef] += p1; } else { block[thiscoef] += m1; } } } } } // Count one block completed in EOB run EOBRUN--; } // Completed MCU, so update state //was BITREAD_SAVE_STATE(cinfo, entropy.bitstate); cinfo.src.input_bytes = br_state.input_bytes; cinfo.src.next_input_byte = br_state.next_input_byte; cinfo.src.bytes_in_buffer = br_state.bytes_in_buffer; entropy.bitstate.get_buffer = get_buffer; entropy.bitstate.bits_left = bits_left; entropy.saved.EOBRUN = EOBRUN; // only part of saved state we need } // Account for restart interval (no-op if not using restarts) entropy.restarts_to_go--; return(true); undoit: // Re-zero any output coefficients that we made newly nonzero while (num_newnz > 0) { block[newnz_pos[--num_newnz]] = 0; } return(false); }
// Decompress and return some data in the single-pass case. // Always attempts to emit one fully interleaved MCU row ("iMCU" row). // Input and output must run in lockstep since we have only a one-MCU buffer. // Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. // // NB: output_buf contains a plane for each component in image, // which we index according to the component's SOF position. static CONSUME_INPUT decompress_onepass(jpeg_decompress cinfo, byte[][][] output_buf) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; d_coef_controller coef = (d_coef_controller)lossyd.coef_private; uint last_MCU_col = cinfo.MCUs_per_row - 1; uint last_iMCU_row = cinfo.total_iMCU_rows - 1; // Loop to process 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 { // Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. for (int i = 0; i < cinfo.blocks_in_MCU; i++) { for (int a = 0; a < DCTSIZE2; a++) { coef.MCU_buffer[i][a] = 0; } } if (!lossyd.entropy_decode_mcu(cinfo, coef.MCU_buffer)) { // Suspension forced; update state counters and exit coef.MCU_vert_offset = yoffset; coef.MCU_ctr = MCU_col_num; return(CONSUME_INPUT.JPEG_SUSPENDED); } // Determine where data should go in output_buf and do the IDCT thing. // We skip dummy blocks at the right and bottom edges (but blkn gets // incremented past them!). Note the inner loop relies on having // allocated the MCU_buffer[] blocks sequentially. 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]; // Don't bother to IDCT an uninteresting component. if (!compptr.component_needed) { blkn += (int)compptr.MCU_blocks; continue; } inverse_DCT_method_ptr inverse_DCT = lossyd.inverse_DCT[compptr.component_index]; int useful_width = (MCU_col_num < last_MCU_col)?compptr.MCU_width:compptr.last_col_width; byte[][] output_ptr = output_buf[compptr.component_index]; uint output_ptr_ind = (uint)yoffset * compptr.DCT_scaled_size; uint start_col = MCU_col_num * (uint)compptr.MCU_sample_width; for (int yindex = 0; yindex < compptr.MCU_height; yindex++) { if (cinfo.input_iMCU_row < last_iMCU_row || yoffset + yindex < compptr.last_row_height) { uint output_col = start_col; for (int xindex = 0; xindex < useful_width; xindex++) { inverse_DCT(cinfo, compptr, coef.MCU_buffer[blkn + xindex], output_ptr, output_ptr_ind, output_col); output_col += compptr.DCT_scaled_size; } } blkn += compptr.MCU_width; output_ptr_ind += compptr.DCT_scaled_size; } } } // Completed an MCU row, but perhaps not an iMCU row coef.MCU_ctr = 0; } // Completed the iMCU row, advance counters for next one cinfo.output_iMCU_row++; if (++(cinfo.input_iMCU_row) < cinfo.total_iMCU_rows) { start_iMCU_row_d_coef(cinfo); return(CONSUME_INPUT.JPEG_ROW_COMPLETED); } // Completed the scan cinfo.inputctl.finish_input_pass(cinfo); return(CONSUME_INPUT.JPEG_SCAN_COMPLETED); }
// Consume input data and store it in the full-image coefficient buffer. // We read as much as one fully interleaved MCU row ("iMCU" row) per call, // ie, v_samp_factor block rows for each component in the scan. // Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. static CONSUME_INPUT consume_data(jpeg_decompress cinfo) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; d_coef_controller coef = (d_coef_controller)lossyd.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. 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)cinfo.input_iMCU_row * compptr.v_samp_factor; // Note: entropy decoder expects buffer to be zeroed, // but this is handled automatically by the memory manager // because we requested a pre-zeroed array. } // 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++) // index of current MCU within row { // 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 fetch the MCU. if (!lossyd.entropy_decode_mcu(cinfo, coef.MCU_buffer)) { // Suspension forced; update state counters and exit coef.MCU_vert_offset = yoffset; coef.MCU_ctr = MCU_col_num; return(CONSUME_INPUT.JPEG_SUSPENDED); } } // Completed an MCU row, but perhaps not an iMCU row coef.MCU_ctr = 0; } // Completed the iMCU row, advance counters for next one if (++(cinfo.input_iMCU_row) < cinfo.total_iMCU_rows) { start_iMCU_row_d_coef(cinfo); return(CONSUME_INPUT.JPEG_ROW_COMPLETED); } // Completed the scan cinfo.inputctl.finish_input_pass(cinfo); return(CONSUME_INPUT.JPEG_SCAN_COMPLETED); }
// Decode and return one MCU's worth of Huffman-compressed coefficients. // The coefficients are reordered from zigzag order into natural array order, // but are not dequantized. // // The i'th block of the MCU is stored into the block pointed to by // MCU_data[i]. WE ASSUME THIS AREA HAS BEEN ZEROED BY THE CALLER. // (Wholesale zeroing is usually a little faster than retail...) // // Returns false if data source requested suspension. In that case no // changes have been made to permanent state. (Exception: some output // coefficients may already have been assigned. This is harmless for // this module, since we'll just re-assign them on the next call.) static bool decode_mcu(jpeg_decompress cinfo, short[][] MCU_data) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; shuff_entropy_decoder entropy = (shuff_entropy_decoder)lossyd.entropy_private; // Process restart marker if needed; may have to suspend if (cinfo.restart_interval != 0) { if (entropy.restarts_to_go == 0) { if (!process_restart_dshuff(cinfo)) { return(false); } } } // If we've run out of data, just leave the MCU set to zeroes. // This way, we return uniform gray for the remainder of the segment. if (!entropy.insufficient_data) { bitread_working_state br_state = new bitread_working_state(); savable_state_sq state; state.last_dc_val = new int[MAX_COMPS_IN_SCAN]; // Load up working state //was BITREAD_STATE_VARS; //was BITREAD_LOAD_STATE(cinfo, entropy.bitstate); br_state.cinfo = cinfo; br_state.input_bytes = cinfo.src.input_bytes; br_state.next_input_byte = cinfo.src.next_input_byte; br_state.bytes_in_buffer = cinfo.src.bytes_in_buffer; ulong get_buffer = entropy.bitstate.get_buffer; int bits_left = entropy.bitstate.bits_left; //was state=entropy.saved; entropy.saved.last_dc_val.CopyTo(state.last_dc_val, 0); // Outer loop handles each block in the MCU for (int blkn = 0; blkn < cinfo.blocks_in_MCU; blkn++) { short[] block = MCU_data[blkn]; d_derived_tbl dctbl = entropy.dc_cur_tbls[blkn]; d_derived_tbl actbl = entropy.ac_cur_tbls[blkn]; int s = 0, k, r; // Decode a single block's worth of coefficients // Section F.2.2.1: decode the DC coefficient difference //was HUFF_DECODE(s, br_state, dctbl, return false, label1); { int nb, look; bool label = false; if (bits_left < HUFF_LOOKAHEAD) { if (!jpeg_fill_bit_buffer(ref br_state, get_buffer, bits_left, 0)) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; if (bits_left < HUFF_LOOKAHEAD) { nb = 1; label = true; if ((s = jpeg_huff_decode(ref br_state, get_buffer, bits_left, dctbl, nb)) < 0) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } } if (!label) { //was look=PEEK_BITS(HUFF_LOOKAHEAD); look = ((int)(get_buffer >> (bits_left - HUFF_LOOKAHEAD))) & ((1 << HUFF_LOOKAHEAD) - 1); if ((nb = dctbl.look_nbits[look]) != 0) { //was DROP_BITS(nb); bits_left -= nb; s = dctbl.look_sym[look]; } else { nb = HUFF_LOOKAHEAD + 1; if ((s = jpeg_huff_decode(ref br_state, get_buffer, bits_left, dctbl, nb)) < 0) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } } } if (s != 0) { //was CHECK_BIT_BUFFER(br_state, s, return false); if (bits_left < s) { if (!jpeg_fill_bit_buffer(ref br_state, get_buffer, bits_left, s)) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } //was r = GET_BITS(s); r = ((int)(get_buffer >> (bits_left -= s))) & ((1 << s) - 1); //was s=HUFF_EXTEND(r, s); s = (r < (1 << (s - 1))?r + (((-1) << s) + 1):r); } if (entropy.dc_needed[blkn]) { // Convert DC difference to actual value, update last_dc_val int ci = cinfo.MCU_membership[blkn]; s += state.last_dc_val[ci]; state.last_dc_val[ci] = s; // Output the DC coefficient (assumes jpeg_natural_order[0] = 0) block[0] = (short)s; } if (entropy.ac_needed[blkn]) { // Section F.2.2.2: decode the AC coefficients // Since zeroes are skipped, output area must be cleared beforehand for (k = 1; k < DCTSIZE2; k++) { //was HUFF_DECODE(s, br_state, actbl, return false, label2); { int nb, look; bool label = false; if (bits_left < HUFF_LOOKAHEAD) { if (!jpeg_fill_bit_buffer(ref br_state, get_buffer, bits_left, 0)) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; if (bits_left < HUFF_LOOKAHEAD) { nb = 1; label = true; if ((s = jpeg_huff_decode(ref br_state, get_buffer, bits_left, actbl, nb)) < 0) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } } if (!label) { //was look=PEEK_BITS(HUFF_LOOKAHEAD); look = ((int)(get_buffer >> (bits_left - HUFF_LOOKAHEAD))) & ((1 << HUFF_LOOKAHEAD) - 1); if ((nb = actbl.look_nbits[look]) != 0) { //was DROP_BITS(nb); bits_left -= nb; s = actbl.look_sym[look]; } else { nb = HUFF_LOOKAHEAD + 1; if ((s = jpeg_huff_decode(ref br_state, get_buffer, bits_left, actbl, nb)) < 0) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } } } r = s >> 4; s &= 15; if (s != 0) { k += r; //was CHECK_BIT_BUFFER(br_state, s, return false); if (bits_left < s) { if (!jpeg_fill_bit_buffer(ref br_state, get_buffer, bits_left, s)) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } //was r = GET_BITS(s); r = ((int)(get_buffer >> (bits_left -= s))) & ((1 << s) - 1); //was s=HUFF_EXTEND(r, s); s = (r < (1 << (s - 1))?r + (((-1) << s) + 1):r); // Output coefficient in natural (dezigzagged) order. // Note: the extra entries in jpeg_natural_order[] will save us // if k >= DCTSIZE2, which could happen if the data is corrupted. block[jpeg_natural_order[k]] = (short)s; } else { if (r != 15) { break; } k += 15; } } } else { // Section F.2.2.2: decode the AC coefficients // In this path we just discard the values for (k = 1; k < DCTSIZE2; k++) { //was HUFF_DECODE(s, br_state, actbl, return false, label3); { int nb, look; bool label = false; if (bits_left < HUFF_LOOKAHEAD) { if (!jpeg_fill_bit_buffer(ref br_state, get_buffer, bits_left, 0)) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; if (bits_left < HUFF_LOOKAHEAD) { nb = 1; label = true; if ((s = jpeg_huff_decode(ref br_state, get_buffer, bits_left, actbl, nb)) < 0) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } } if (!label) { //was look=PEEK_BITS(HUFF_LOOKAHEAD); look = ((int)(get_buffer >> (bits_left - HUFF_LOOKAHEAD))) & ((1 << HUFF_LOOKAHEAD) - 1); if ((nb = actbl.look_nbits[look]) != 0) { //was DROP_BITS(nb); bits_left -= nb; s = actbl.look_sym[look]; } else { nb = HUFF_LOOKAHEAD + 1; if ((s = jpeg_huff_decode(ref br_state, get_buffer, bits_left, actbl, nb)) < 0) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } } } r = s >> 4; s &= 15; if (s != 0) { k += r; //was CHECK_BIT_BUFFER(br_state, s, return false); if (bits_left < s) { if (!jpeg_fill_bit_buffer(ref br_state, get_buffer, bits_left, s)) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } //was DROP_BITS(s); bits_left -= s; } else { if (r != 15) { break; } k += 15; } } } } // Completed MCU, so update state //was BITREAD_SAVE_STATE(cinfo, entropy.bitstate); cinfo.src.input_bytes = br_state.input_bytes; cinfo.src.next_input_byte = br_state.next_input_byte; cinfo.src.bytes_in_buffer = br_state.bytes_in_buffer; entropy.bitstate.get_buffer = get_buffer; entropy.bitstate.bits_left = bits_left; //was entropy.saved=state; state.last_dc_val.CopyTo(entropy.saved.last_dc_val, 0); } // Account for restart interval (no-op if not using restarts) entropy.restarts_to_go--; return(true); }
// Decompress and return some data in the multi-pass case. // Always attempts to emit one fully interleaved MCU row ("iMCU" row). // Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. // // NB: output_buf contains a plane for each component in image. static CONSUME_INPUT decompress_data(jpeg_decompress cinfo, byte[][][] output_buf) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; d_coef_controller coef = (d_coef_controller)lossyd.coef_private; uint last_iMCU_row = cinfo.total_iMCU_rows - 1; // Force some input to be done if we are getting ahead of the input. while (cinfo.input_scan_number < cinfo.output_scan_number || (cinfo.input_scan_number == cinfo.output_scan_number && cinfo.input_iMCU_row <= cinfo.output_iMCU_row)) { if (cinfo.inputctl.consume_input(cinfo) == CONSUME_INPUT.JPEG_SUSPENDED) { return(CONSUME_INPUT.JPEG_SUSPENDED); } } // OK, output from the arrays. for (int ci = 0; ci < cinfo.num_components; ci++) { jpeg_component_info compptr = cinfo.comp_info[ci]; // Don't bother to IDCT an uninteresting component. if (!compptr.component_needed) { continue; } // Align the buffer for this component. short[][][] buffer = coef.whole_image[ci]; uint buffer_ind = cinfo.output_iMCU_row * (uint)compptr.v_samp_factor; // Count non-dummy DCT block rows in this iMCU row. int block_rows; if (cinfo.output_iMCU_row < last_iMCU_row) { block_rows = compptr.v_samp_factor; } else { // NB: can't use last_row_height here; it is input-side-dependent! block_rows = (int)(compptr.height_in_blocks % compptr.v_samp_factor); if (block_rows == 0) { block_rows = compptr.v_samp_factor; } } inverse_DCT_method_ptr inverse_DCT = lossyd.inverse_DCT[ci]; byte[][] output_ptr = output_buf[ci]; uint output_ptr_ind = 0; // Loop over all DCT blocks to be processed. for (int block_row = 0; block_row < block_rows; block_row++) { short[][] buffer_ptr = buffer[buffer_ind + block_row]; uint output_col = 0; for (uint block_num = 0; block_num < compptr.width_in_blocks; block_num++) { inverse_DCT(cinfo, compptr, buffer_ptr[block_num], output_ptr, output_ptr_ind, output_col); output_col += compptr.DCT_scaled_size; } output_ptr_ind += compptr.DCT_scaled_size; } } if (++(cinfo.output_iMCU_row) < cinfo.total_iMCU_rows) { return(CONSUME_INPUT.JPEG_ROW_COMPLETED); } return(CONSUME_INPUT.JPEG_SCAN_COMPLETED); }
// Initialize for a Huffman-compressed scan. static void start_pass_phuff_decoder(jpeg_decompress cinfo) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; phuff_entropy_decoder entropy = (phuff_entropy_decoder)lossyd.entropy_private; bool is_DC_band = (cinfo.Ss == 0); // Validate scan parameters bool bad = false; if (is_DC_band) { if (cinfo.Se != 0) { bad = true; } } else { // need not check Ss/Se < 0 since they came from unsigned bytes if (cinfo.Ss > cinfo.Se || cinfo.Se >= DCTSIZE2) { bad = true; } // AC scans may have only one component if (cinfo.comps_in_scan != 1) { bad = true; } } if (cinfo.Ah != 0) { // Successive approximation refinement scan: must have Al = Ah-1. if (cinfo.Al != cinfo.Ah - 1) { bad = true; } } // Arguably the maximum Al value should be less than 13 for 8-bit precision, // but the spec doesn't say so, and we try to be liberal about what we // accept. Note: large Al values could result in out-of-range DC // coefficients during early scans, leading to bizarre displays due to // overflows in the IDCT math. But we won't crash. if (cinfo.Al > 13) { bad = true; // need not check for < 0 } if (bad) { ERREXIT4(cinfo, J_MESSAGE_CODE.JERR_BAD_PROGRESSION, cinfo.Ss, cinfo.Se, cinfo.Ah, cinfo.Al); } // Update progression status, and verify that scan order is legal. // Note that inter-scan inconsistencies are treated as warnings // not fatal errors ... not clear if this is right way to behave. for (int ci = 0; ci < cinfo.comps_in_scan; ci++) { int cindex = cinfo.cur_comp_info[ci].component_index; int[] coef_bit_ptr = cinfo.coef_bits[cindex]; if (!is_DC_band && coef_bit_ptr[0] < 0) { WARNMS2(cinfo, J_MESSAGE_CODE.JWRN_BOGUS_PROGRESSION, cindex, 0); // AC without prior DC scan } for (int coefi = cinfo.Ss; coefi <= cinfo.Se; coefi++) { int expected = (coef_bit_ptr[coefi] < 0)?0:coef_bit_ptr[coefi]; if (cinfo.Ah != expected) { WARNMS2(cinfo, J_MESSAGE_CODE.JWRN_BOGUS_PROGRESSION, cindex, coefi); } coef_bit_ptr[coefi] = cinfo.Al; } } // Select MCU decoding routine if (cinfo.Ah == 0) { if (is_DC_band) { lossyd.entropy_decode_mcu = decode_mcu_DC_first; } else { lossyd.entropy_decode_mcu = decode_mcu_AC_first; } } else { if (is_DC_band) { lossyd.entropy_decode_mcu = decode_mcu_DC_refine; } else { lossyd.entropy_decode_mcu = decode_mcu_AC_refine; } } for (int ci = 0; ci < cinfo.comps_in_scan; ci++) { jpeg_component_info compptr = cinfo.cur_comp_info[ci]; // Make sure requested tables are present, and compute derived tables. // We may build same derived table more than once, but it's not expensive. if (is_DC_band) { if (cinfo.Ah == 0) { // DC refinement needs no table int tbl = compptr.dc_tbl_no; jpeg_make_d_derived_tbl(cinfo, true, tbl, ref entropy.derived_tbls[tbl]); } } else { int tbl = compptr.ac_tbl_no; jpeg_make_d_derived_tbl(cinfo, false, tbl, ref entropy.derived_tbls[tbl]); // remember the single active table entropy.ac_derived_tbl = entropy.derived_tbls[tbl]; } // Initialize DC predictions to 0 entropy.saved.last_dc_val[ci] = 0; } // Initialize bitread state variables entropy.bitstate.bits_left = 0; entropy.bitstate.get_buffer = 0; // unnecessary, but keeps Purify quiet entropy.insufficient_data = false; // Initialize private state variables entropy.saved.EOBRUN = 0; // Initialize restart counter entropy.restarts_to_go = cinfo.restart_interval; }
// Huffman MCU decoding. // Each of these routines decodes and returns one MCU's worth of // Huffman-compressed coefficients. // The coefficients are reordered from zigzag order into natural array order, // but are not dequantized. // // The i'th block of the MCU is stored into the block pointed to by // MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER. // // We return false if data source requested suspension. In that case no // changes have been made to permanent state. (Exception: some output // coefficients may already have been assigned. This is harmless for // spectral selection, since we'll just re-assign them on the next call. // Successive approximation AC refinement has to be more careful, however.) // MCU decoding for DC initial scan (either spectral selection, // or first pass of successive approximation). static bool decode_mcu_DC_first(jpeg_decompress cinfo, short[][] MCU_data) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; phuff_entropy_decoder entropy = (phuff_entropy_decoder)lossyd.entropy_private; int Al = cinfo.Al; // Process restart marker if needed; may have to suspend if (cinfo.restart_interval != 0) { if (entropy.restarts_to_go == 0) { if (!process_restart_dphuff(cinfo)) { return(false); } } } // If we've run out of data, just leave the MCU set to zeroes. // This way, we return uniform gray for the remainder of the segment. if (!entropy.insufficient_data) { // Load up working state //was BITREAD_STATE_VARS; bitread_working_state br_state = new bitread_working_state(); savable_state state; state.last_dc_val = new int[MAX_COMPS_IN_SCAN]; //was BITREAD_LOAD_STATE(cinfo, entropy.bitstate); br_state.cinfo = cinfo; br_state.input_bytes = cinfo.src.input_bytes; br_state.next_input_byte = cinfo.src.next_input_byte; br_state.bytes_in_buffer = cinfo.src.bytes_in_buffer; ulong get_buffer = entropy.bitstate.get_buffer; int bits_left = entropy.bitstate.bits_left; //was state=entropy.saved; state.EOBRUN = entropy.saved.EOBRUN; entropy.saved.last_dc_val.CopyTo(state.last_dc_val, 0); // Outer loop handles each block in the MCU for (int blkn = 0; blkn < cinfo.blocks_in_MCU; blkn++) { short[] block = MCU_data[blkn]; int ci = cinfo.MCU_membership[blkn]; jpeg_component_info compptr = cinfo.cur_comp_info[ci]; d_derived_tbl tbl = entropy.derived_tbls[compptr.dc_tbl_no]; int s = 0; // Decode a single block's worth of coefficients // Section F.2.2.1: decode the DC coefficient difference //was HUFF_DECODE(s, br_state, tbl, return false, label1); { int nb, look; bool label = false; if (bits_left < HUFF_LOOKAHEAD) { if (!jpeg_fill_bit_buffer(ref br_state, get_buffer, bits_left, 0)) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; if (bits_left < HUFF_LOOKAHEAD) { nb = 1; label = true; if ((s = jpeg_huff_decode(ref br_state, get_buffer, bits_left, tbl, nb)) < 0) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } } if (!label) { //was look=PEEK_BITS(HUFF_LOOKAHEAD); look = ((int)(get_buffer >> (bits_left - HUFF_LOOKAHEAD))) & ((1 << HUFF_LOOKAHEAD) - 1); if ((nb = tbl.look_nbits[look]) != 0) { //was DROP_BITS(nb); bits_left -= nb; s = tbl.look_sym[look]; } else { nb = HUFF_LOOKAHEAD + 1; if ((s = jpeg_huff_decode(ref br_state, get_buffer, bits_left, tbl, nb)) < 0) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } } } if (s != 0) { //was CHECK_BIT_BUFFER(br_state, s, return false); if (bits_left < s) { if (!jpeg_fill_bit_buffer(ref br_state, get_buffer, bits_left, s)) { return(false); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } //was r = GET_BITS(s); int r = ((int)(get_buffer >> (bits_left -= s))) & ((1 << s) - 1); //was s=HUFF_EXTEND(r, s); s = (r < (1 << (s - 1))?r + (((-1) << s) + 1):r); } // Convert DC difference to actual value, update last_dc_val s += state.last_dc_val[ci]; state.last_dc_val[ci] = s; // Scale and output the coefficient (assumes jpeg_natural_order[0]=0) block[0] = (short)(s << Al); } // Completed MCU, so update state //was BITREAD_SAVE_STATE(cinfo, entropy.bitstate); cinfo.src.input_bytes = br_state.input_bytes; cinfo.src.next_input_byte = br_state.next_input_byte; cinfo.src.bytes_in_buffer = br_state.bytes_in_buffer; entropy.bitstate.get_buffer = get_buffer; entropy.bitstate.bits_left = bits_left; //was entropy.saved=state; entropy.saved.EOBRUN = state.EOBRUN; state.last_dc_val.CopyTo(entropy.saved.last_dc_val, 0); } // Account for restart interval (no-op if not using restarts) entropy.restarts_to_go--; return(true); }
// Variant of decompress_data for use when doing block smoothing. static CONSUME_INPUT decompress_smooth_data(jpeg_decompress cinfo, byte[][][] output_buf) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; d_coef_controller coef = (d_coef_controller)lossyd.coef_private; // Force some input to be done if we are getting ahead of the input. while (cinfo.input_scan_number <= cinfo.output_scan_number && !cinfo.inputctl.eoi_reached) { if (cinfo.input_scan_number == cinfo.output_scan_number) { // If input is working on current scan, we ordinarily want it to // have completed the current row. But if input scan is DC, // we want it to keep one row ahead so that next block row's DC // values are up to date. uint delta = (cinfo.Ss == 0)?1u:0u; if (cinfo.input_iMCU_row > cinfo.output_iMCU_row + delta) { break; } } if (cinfo.inputctl.consume_input(cinfo) == CONSUME_INPUT.JPEG_SUSPENDED) { return(CONSUME_INPUT.JPEG_SUSPENDED); } } uint last_iMCU_row = cinfo.total_iMCU_rows - 1; short[] workspace = new short[DCTSIZE2]; // OK, output from the arrays. for (int ci = 0; ci < cinfo.num_components; ci++) { jpeg_component_info compptr = cinfo.comp_info[ci]; // Don't bother to IDCT an uninteresting component. if (!compptr.component_needed) { continue; } // Count non-dummy DCT block rows in this iMCU row. int block_rows, access_rows; bool last_row; if (cinfo.output_iMCU_row < last_iMCU_row) { block_rows = compptr.v_samp_factor; access_rows = block_rows * 2; // this and next iMCU row last_row = false; } else { // NB: can't use last_row_height here; it is input-side-dependent! block_rows = (int)(compptr.height_in_blocks % compptr.v_samp_factor); if (block_rows == 0) { block_rows = compptr.v_samp_factor; } access_rows = block_rows; // this iMCU row only last_row = true; } // Align the buffer for this component. bool first_row; short[][][] buffer; int buffer_ind; if (cinfo.output_iMCU_row > 0) { access_rows += compptr.v_samp_factor; // prior iMCU row too buffer = coef.whole_image[ci]; buffer_ind = (int)cinfo.output_iMCU_row * compptr.v_samp_factor; // point to current iMCU row first_row = false; } else { buffer = coef.whole_image[ci]; buffer_ind = 0; first_row = true; } // Fetch component-dependent info int[] coef_bits = coef.coef_bits_latch[ci]; JQUANT_TBL quanttbl = compptr.quant_table; int Q00 = quanttbl.quantval[0]; int Q01 = quanttbl.quantval[Q01_POS]; int Q10 = quanttbl.quantval[Q10_POS]; int Q20 = quanttbl.quantval[Q20_POS]; int Q11 = quanttbl.quantval[Q11_POS]; int Q02 = quanttbl.quantval[Q02_POS]; inverse_DCT_method_ptr inverse_DCT = lossyd.inverse_DCT[ci]; uint output_buf_ind = 0; // Loop over all DCT blocks to be processed. for (int block_row = 0; block_row < block_rows; block_row++) { short[][] buffer_ptr = buffer[buffer_ind + block_row]; short[][] prev_block_row; short[][] next_block_row; if (first_row && block_row == 0) { prev_block_row = buffer_ptr; } else { prev_block_row = buffer[buffer_ind + block_row - 1]; } if (last_row && block_row == block_rows - 1) { next_block_row = buffer_ptr; } else { next_block_row = buffer[buffer_ind + block_row + 1]; } // We fetch the surrounding DC values using a sliding-register approach. // Initialize all nine here so as to do the right thing on narrow pics. int DC1, DC2, DC3, DC4, DC5, DC6, DC7, DC8, DC9; DC1 = DC2 = DC3 = (int)prev_block_row[0][0]; DC4 = DC5 = DC6 = (int)buffer_ptr[0][0]; DC7 = DC8 = DC9 = (int)next_block_row[0][0]; int ind = 1; uint output_col = 0; uint last_block_column = compptr.width_in_blocks - 1; for (uint block_num = 0; block_num <= last_block_column; block_num++) { // Fetch current DCT block into workspace so we can modify it. buffer_ptr.CopyTo(workspace, 0); // Update DC values if (block_num < last_block_column) { DC3 = (int)prev_block_row[ind][0]; DC6 = (int)buffer_ptr[ind][0]; DC9 = (int)next_block_row[ind][0]; } // Compute coefficient estimates per K.8. // An estimate is applied only if coefficient is still zero, // and is not known to be fully accurate. // AC01 int Al = coef_bits[1]; if (Al != 0 && workspace[1] == 0) { int num = 36 * Q00 * (DC4 - DC6); int pred; if (num >= 0) { pred = (int)(((Q01 << 7) + num) / (Q01 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } } else { pred = (int)(((Q01 << 7) - num) / (Q01 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } pred = -pred; } workspace[1] = (short)pred; } // AC10 Al = coef_bits[2]; if (Al != 0 && workspace[8] == 0) { int num = 36 * Q00 * (DC2 - DC8); int pred; if (num >= 0) { pred = (int)(((Q10 << 7) + num) / (Q10 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } } else { pred = (int)(((Q10 << 7) - num) / (Q10 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } pred = -pred; } workspace[8] = (short)pred; } // AC20 Al = coef_bits[3]; if (Al != 0 && workspace[16] == 0) { int num = 9 * Q00 * (DC2 + DC8 - 2 * DC5); int pred; if (num >= 0) { pred = (int)(((Q20 << 7) + num) / (Q20 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } } else { pred = (int)(((Q20 << 7) - num) / (Q20 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } pred = -pred; } workspace[16] = (short)pred; } // AC11 Al = coef_bits[4]; if (Al != 0 && workspace[9] == 0) { int num = 5 * Q00 * (DC1 - DC3 - DC7 + DC9); int pred; if (num >= 0) { pred = (int)(((Q11 << 7) + num) / (Q11 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } } else { pred = (int)(((Q11 << 7) - num) / (Q11 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } pred = -pred; } workspace[9] = (short)pred; } // AC02 Al = coef_bits[5]; if (Al != 0 && workspace[2] == 0) { int num = 9 * Q00 * (DC4 + DC6 - 2 * DC5); int pred; if (num >= 0) { pred = (int)(((Q02 << 7) + num) / (Q02 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } } else { pred = (int)(((Q02 << 7) - num) / (Q02 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } pred = -pred; } workspace[2] = (short)pred; } // OK, do the IDCT inverse_DCT(cinfo, compptr, workspace, output_buf[ci], output_buf_ind, output_col); // Advance for next column DC1 = DC2; DC2 = DC3; DC4 = DC5; DC5 = DC6; DC7 = DC8; DC8 = DC9; ind++; output_col += compptr.DCT_scaled_size; } output_buf_ind += compptr.DCT_scaled_size; } } if (++(cinfo.output_iMCU_row) < cinfo.total_iMCU_rows) { return(CONSUME_INPUT.JPEG_ROW_COMPLETED); } return(CONSUME_INPUT.JPEG_SCAN_COMPLETED); }
// Determine whether block smoothing is applicable and safe. // We also latch the current states of the coef_bits[] entries for the // AC coefficients; otherwise, if the input side of the decompressor // advances into a new scan, we might think the coefficients are known // more accurately than they really are. static bool smoothing_ok(jpeg_decompress cinfo) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; d_coef_controller coef = (d_coef_controller)lossyd.coef_private; if (cinfo.process != J_CODEC_PROCESS.JPROC_PROGRESSIVE || cinfo.coef_bits == null) { return(false); } // Allocate latch area if not already done if (coef.coef_bits_latch == null) { try { coef.coef_bits_latch = new int[cinfo.num_components][]; for (int i = 0; i < cinfo.num_components; i++) { coef.coef_bits_latch[i] = new int[SAVED_COEFS]; } } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } } bool smoothing_useful = false; for (int ci = 0; ci < cinfo.num_components; ci++) { jpeg_component_info compptr = cinfo.comp_info[ci]; // All components' quantization values must already be latched. JQUANT_TBL qtable = compptr.quant_table; if (qtable == null) { return(false); } // Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. if (qtable.quantval[0] == 0 || qtable.quantval[Q01_POS] == 0 || qtable.quantval[Q10_POS] == 0 || qtable.quantval[Q20_POS] == 0 || qtable.quantval[Q11_POS] == 0 || qtable.quantval[Q02_POS] == 0) { return(false); } // DC values must be at least partly known for all components. int[] coef_bits = cinfo.coef_bits[ci]; if (coef_bits[0] < 0) { return(false); } // Block smoothing is helpful if some AC coefficients remain inaccurate. for (int coefi = 1; coefi <= 5; coefi++) { coef.coef_bits_latch[ci][coefi] = coef_bits[coefi]; if (coef_bits[coefi] != 0) { smoothing_useful = true; } } } return(smoothing_useful); }