static void scaler_start_pass(jpeg_decompress cinfo) { jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef; scaler scaler = (scaler)losslsd.scaler_private; // Downscale by the difference in the input vs. output precision. If the // output precision >= input precision, then do not downscale. int downscale = BITS_IN_JSAMPLE < cinfo.data_precision?cinfo.data_precision - BITS_IN_JSAMPLE:0; scaler.scale_factor = cinfo.Al - downscale; // Set scaler functions based on scale_factor (positive = left shift) if (scaler.scale_factor > 0) { losslsd.scaler_scale = simple_upscale; } else if (scaler.scale_factor < 0) { scaler.scale_factor = -scaler.scale_factor; losslsd.scaler_scale = simple_downscale; } else { losslsd.scaler_scale = noscale; } }
//#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_dlhuff(jpeg_decompress cinfo) { jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef; lhuff_entropy_decoder entropy = (lhuff_entropy_decoder)losslsd.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); } // 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); }
// Undifferencer for the first row in a scan or restart interval. The first // sample in the row is undifferenced using the special predictor constant // x=2^(P-Pt-1). The rest of the samples are undifferenced using the // 1-D horizontal predictor (1). static void jpeg_undifference_first_row(jpeg_decompress cinfo, int comp_index, int[] diff_buf, int[] prev_row, int[] undiff_buf, uint width) { jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef; int Ra = (diff_buf[0] + (1 << (cinfo.data_precision - cinfo.Al - 1))) & 0xFFFF; undiff_buf[0] = Ra; for (uint xindex = 1; xindex < width; xindex++) { Ra = (diff_buf[xindex] + Ra) & 0xFFFF; undiff_buf[xindex] = Ra; } // Now that we have undifferenced the first row, we want to use the // undifferencer which corresponds to the predictor specified in the // scan header. switch (cinfo.Ss) { case 1: losslsd.predict_undifference[comp_index] = jpeg_undifference1; break; case 2: losslsd.predict_undifference[comp_index] = jpeg_undifference2; break; case 3: losslsd.predict_undifference[comp_index] = jpeg_undifference3; break; case 4: losslsd.predict_undifference[comp_index] = jpeg_undifference4; break; case 5: losslsd.predict_undifference[comp_index] = jpeg_undifference5; break; case 6: losslsd.predict_undifference[comp_index] = jpeg_undifference6; break; case 7: losslsd.predict_undifference[comp_index] = jpeg_undifference7; break; } }
// Module initialization routine for the undifferencer. static void jinit_undifferencer(jpeg_decompress cinfo) { jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef; losslsd.predict_start_pass = start_pass_d_pred; losslsd.predict_process_restart = start_pass_d_pred; }
// Reset within-iMCU-row counters for a new row (input side) static void start_iMCU_row_d_diff(jpeg_decompress cinfo) { jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef; d_diff_controller diff = (d_diff_controller)losslsd.diff_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) { diff.MCU_rows_per_iMCU_row = 1; } else { if (cinfo.input_iMCU_row < (cinfo.total_iMCU_rows - 1)) { diff.MCU_rows_per_iMCU_row = (uint)cinfo.cur_comp_info[0].v_samp_factor; } else { diff.MCU_rows_per_iMCU_row = (uint)cinfo.cur_comp_info[0].last_row_height; } } diff.MCU_ctr = 0; diff.MCU_vert_offset = 0; }
// Initialize for an input processing pass. static void start_input_pass_ls(jpeg_decompress cinfo) { jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef; losslsd.entropy_start_pass(cinfo); losslsd.predict_start_pass(cinfo); losslsd.scaler_start_pass(cinfo); losslsd.diff_start_input_pass(cinfo); }
static void simple_downscale(jpeg_decompress cinfo, int[] diff_buf, byte[] output_buf, uint width) { jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef; scaler scaler = (scaler)losslsd.scaler_private; int scale_factor = scaler.scale_factor; for (uint xindex = 0; xindex < width; xindex++) { output_buf[xindex] = (byte)(diff_buf[xindex] >> scale_factor); } }
// Initialize for a Huffman-compressed scan. static void start_pass_lhuff_decoder(jpeg_decompress cinfo) { jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef; lhuff_entropy_decoder entropy = (lhuff_entropy_decoder)losslsd.entropy_private; 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; // Make sure requested tables are present if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS || cinfo.dc_huff_tbl_ptrs[dctbl] == null) { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_NO_HUFF_TABLE, dctbl); } // 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.derived_tbls[dctbl]); } // Precalculate decoding info for each sample in an MCU of this scan int ptrn = 0; for (int sampn = 0; sampn < cinfo.blocks_in_MCU;) { jpeg_component_info compptr = cinfo.cur_comp_info[cinfo.MCU_membership[sampn]]; int ci = compptr.component_index; for (int yoffset = 0; yoffset < compptr.MCU_height; yoffset++, ptrn++) { // Precalculate the setup info for each output pointer entropy.output_ptr_info[ptrn].ci = ci; entropy.output_ptr_info[ptrn].yoffset = yoffset; entropy.output_ptr_info[ptrn].MCU_width = compptr.MCU_width; for (int xoffset = 0; xoffset < compptr.MCU_width; xoffset++, sampn++) { // Precalculate the output pointer index for each sample entropy.output_ptr_index[sampn] = ptrn; // Precalculate which table to use for each sample entropy.cur_tbls[sampn] = entropy.derived_tbls[compptr.dc_tbl_no]; } } } entropy.num_output_ptrs = ptrn; // Initialize bitread state variables entropy.bitstate.bits_left = 0; entropy.bitstate.get_buffer = 0; // unnecessary, but keeps Purify quiet entropy.insufficient_data = false; }
// Output some data from the full-image buffer sample 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 output_data_d_diff(jpeg_decompress cinfo, byte[][][] output_buf) { jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef; d_diff_controller diff = (d_diff_controller)losslsd.diff_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]; // Align the buffer for this component. byte[][] buffer = diff.whole_image[ci]; int samp_rows; if (cinfo.output_iMCU_row < last_iMCU_row) { samp_rows = compptr.v_samp_factor; } else { // NB: can't use last_row_height here; it is input-side-dependent! samp_rows = (int)(compptr.height_in_blocks % compptr.v_samp_factor); if (samp_rows == 0) { samp_rows = compptr.v_samp_factor; } } for (int row = 0; row < samp_rows; row++) { Array.Copy(buffer[cinfo.output_iMCU_row * compptr.v_samp_factor + row], output_buf[ci][row], compptr.width_in_blocks); } } if (++(cinfo.output_iMCU_row) < cinfo.total_iMCU_rows) { return(CONSUME_INPUT.JPEG_ROW_COMPLETED); } return(CONSUME_INPUT.JPEG_SCAN_COMPLETED); }
// Initialize difference buffer controller. static void jinit_d_diff_controller(jpeg_decompress cinfo, bool need_full_buffer) { jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef; d_diff_controller diff = null; try { diff = new d_diff_controller(); } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } losslsd.diff_private = diff; losslsd.diff_start_input_pass = start_input_pass_d_diff; losslsd.start_output_pass = start_output_pass_d_diff; // Create the [un]difference buffers. for (int ci = 0; ci < cinfo.num_components; ci++) { jpeg_component_info compptr = cinfo.comp_info[ci]; diff.diff_buf[ci] = alloc_darray(cinfo, (uint)jround_up(compptr.width_in_blocks, compptr.h_samp_factor), (uint)compptr.v_samp_factor); diff.undiff_buf[ci] = alloc_darray(cinfo, (uint)jround_up(compptr.width_in_blocks, compptr.h_samp_factor), (uint)compptr.v_samp_factor); } if (need_full_buffer) { #if D_MULTISCAN_FILES_SUPPORTED // Allocate a full-image array for each component. for (int ci = 0; ci < cinfo.num_components; ci++) { jpeg_component_info compptr = cinfo.comp_info[ci]; diff.whole_image[ci] = alloc_sarray(cinfo, (uint)jround_up(compptr.width_in_blocks, compptr.h_samp_factor), (uint)jround_up(compptr.height_in_blocks, compptr.v_samp_factor)); } losslsd.consume_data = consume_data_d_diff; losslsd.decompress_data = output_data_d_diff; #else ERREXIT(cinfo, J_MESSAGE_CODE.JERR_NOT_COMPILED); #endif } else { losslsd.consume_data = dummy_consume_data_d_diff; losslsd.decompress_data = decompress_data_d_diff; diff.whole_image[0] = null; // flag for no arrays } }
static void jinit_d_scaler(jpeg_decompress cinfo) { jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef; scaler scaler = null; try { scaler = new scaler(); } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } losslsd.scaler_private = scaler; losslsd.scaler_start_pass = scaler_start_pass; }
// Check for a restart marker & resynchronize decoder, undifferencer. // Returns false if must suspend. static bool process_restart_d_diff(jpeg_decompress cinfo) { jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef; d_diff_controller diff = (d_diff_controller)losslsd.diff_private; if (!losslsd.entropy_process_restart(cinfo)) { return(false); } losslsd.predict_process_restart(cinfo); // Reset restart counter diff.restart_rows_to_go = cinfo.restart_interval / cinfo.MCUs_per_row; return(true); }
// Initialize for an input processing pass. static void start_input_pass_d_diff(jpeg_decompress cinfo) { jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef; d_diff_controller diff = (d_diff_controller)losslsd.diff_private; // Check that the restart interval is an integer multiple of the number // of MCU in an MCU-row. if (cinfo.restart_interval % cinfo.MCUs_per_row != 0) { ERREXIT2(cinfo, J_MESSAGE_CODE.JERR_BAD_RESTART, (int)cinfo.restart_interval, (int)cinfo.MCUs_per_row); } // Initialize restart counter diff.restart_rows_to_go = cinfo.restart_interval / cinfo.MCUs_per_row; cinfo.input_iMCU_row = 0; start_iMCU_row_d_diff(cinfo); }
// Initialize the lossless decompression codec. // This is called only once, during master selection. static void jinit_lossless_d_codec(jpeg_decompress cinfo) { jpeg_lossless_d_codec losslsd = null; // Create subobject try { losslsd = new jpeg_lossless_d_codec(); } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } cinfo.coef = losslsd; // Initialize sub-modules // Entropy decoding: either Huffman or arithmetic coding. if (cinfo.arith_code) { ERREXIT(cinfo, J_MESSAGE_CODE.JERR_ARITH_NOTIMPL); } else { jinit_lhuff_decoder(cinfo); } // Undifferencer jinit_undifferencer(cinfo); // Scaler jinit_d_scaler(cinfo); bool use_c_buffer = cinfo.inputctl.has_multiple_scans || cinfo.buffered_image; jinit_d_diff_controller(cinfo, use_c_buffer); // Initialize method pointers. // // Note: consume_data, start_output_pass and decompress_data are // assigned in jddiffct.cs. losslsd.calc_output_dimensions = calc_output_dimensions_ls; losslsd.start_input_pass = start_input_pass_ls; }
// Initialize the lossless decompression codec. // This is called only once, during master selection. static void jinit_lossless_d_codec(jpeg_decompress cinfo) { jpeg_lossless_d_codec losslsd=null; // Create subobject try { losslsd=new jpeg_lossless_d_codec(); } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } cinfo.coef=losslsd; // Initialize sub-modules // Entropy decoding: either Huffman or arithmetic coding. if(cinfo.arith_code) { ERREXIT(cinfo, J_MESSAGE_CODE.JERR_ARITH_NOTIMPL); } else { jinit_lhuff_decoder(cinfo); } // Undifferencer jinit_undifferencer(cinfo); // Scaler jinit_d_scaler(cinfo); bool use_c_buffer=cinfo.inputctl.has_multiple_scans||cinfo.buffered_image; jinit_d_diff_controller(cinfo, use_c_buffer); // Initialize method pointers. // // Note: consume_data, start_output_pass and decompress_data are // assigned in jddiffct.cs. losslsd.calc_output_dimensions=calc_output_dimensions_ls; losslsd.start_input_pass=start_input_pass_ls; }
// Consume input data and store it in the full-image sample buffer. // We read as much as one fully interleaved MCU row ("iMCU" row) per call, // ie, v_samp_factor rows for each component in the scan. // Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. static CONSUME_INPUT consume_data_d_diff(jpeg_decompress cinfo) { jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef; d_diff_controller diff = (d_diff_controller)losslsd.diff_private; uint last_iMCU_row = cinfo.total_iMCU_rows - 1; byte[][][] buffer = new byte[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 comp = 0; comp < cinfo.comps_in_scan; comp++) { jpeg_component_info compptr = cinfo.cur_comp_info[comp]; int ci = compptr.component_index; buffer[ci] = diff.whole_image[ci]; buffer_ind[ci] = (int)cinfo.input_iMCU_row * compptr.v_samp_factor; } return(decompress_data_d_diff(cinfo, buffer, buffer_ind)); }
// Initialize for an input processing pass. static void start_pass_d_pred(jpeg_decompress cinfo) { jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef; // Check that the scan parameters Ss, Se, Ah, Al are OK for lossless JPEG. // // Ss is the predictor selection value (psv). Legal values for sequential // lossless JPEG are: 1 <= psv <= 7. // // Se and Ah are not used and should be zero. // // Al specifies the point transform (Pt). Legal values are: 0 <= Pt <= 15. if (cinfo.Ss < 1 || cinfo.Ss > 7 || cinfo.Se != 0 || cinfo.Ah != 0 || cinfo.Al > 15) // need not check for < 0 { ERREXIT4(cinfo, J_MESSAGE_CODE.JERR_BAD_LOSSLESS, cinfo.Ss, cinfo.Se, cinfo.Ah, cinfo.Al); } // Set undifference functions to first row function for (int ci = 0; ci < cinfo.num_components; ci++) { losslsd.predict_undifference[ci] = jpeg_undifference_first_row; } }
// Module initialization routine for lossless Huffman entropy decoding. public static void jinit_lhuff_decoder(jpeg_decompress cinfo) { jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef; lhuff_entropy_decoder entropy = null; try { entropy = new lhuff_entropy_decoder(); } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } losslsd.entropy_private = entropy; losslsd.entropy_start_pass = start_pass_lhuff_decoder; losslsd.entropy_process_restart = process_restart_dlhuff; losslsd.entropy_decode_mcus = decode_mcus_dlhuff; // Mark tables unallocated for (int i = 0; i < NUM_HUFF_TBLS; i++) { entropy.derived_tbls[i] = null; } }
// Decode and return nMCU's worth of Huffman-compressed differences. // Each MCU is also disassembled and placed accordingly in diff_buf. // // MCU_col_num specifies the column of the first MCU being requested within // the MCU-row. This tells us where to position the output row pointers in // diff_buf. // // Returns the number of MCUs decoded. This may be less than nMCU if data // source requested suspension. In that case no changes have been made to // permanent state. (Exception: some output differences may already have // been assigned. This is harmless for this module, since we'll just // re-assign them on the next call.) static uint decode_mcus_dlhuff(jpeg_decompress cinfo, int[][][] diff_buf, uint MCU_row_num, uint MCU_col_num, uint nMCU) { jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef; lhuff_entropy_decoder entropy = (lhuff_entropy_decoder)losslsd.entropy_private; // Set output pointer locations based on MCU_col_num for (int ptrn = 0; ptrn < entropy.num_output_ptrs; ptrn++) { int ci = entropy.output_ptr_info[ptrn].ci; int yoffset = entropy.output_ptr_info[ptrn].yoffset; int MCU_width = entropy.output_ptr_info[ptrn].MCU_width; entropy.output_ptr[ptrn] = diff_buf[ci][MCU_row_num + yoffset]; entropy.output_ptr_ind[ptrn] = (int)(MCU_col_num * MCU_width); } // If we've run out of data, zero out the buffers and return. // By resetting the undifferencer, the output samples will be CENTERJSAMPLE. // // NB: We should find a way to do this without interacting with the // undifferencer module directly. if (entropy.insufficient_data) { for (int ptrn = 0; ptrn < entropy.num_output_ptrs; ptrn++) { for (int i = 0; i < nMCU * entropy.output_ptr_info[ptrn].MCU_width; i++) { entropy.output_ptr[ptrn][entropy.output_ptr_ind[ptrn] + i] = 0; } } losslsd.predict_process_restart(cinfo); } else { // 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 the number of MCU requested for (uint mcu_num = 0; mcu_num < nMCU; mcu_num++) { // Inner loop handles the samples in the MCU for (int sampn = 0; sampn < cinfo.blocks_in_MCU; sampn++) { d_derived_tbl dctbl = entropy.cur_tbls[sampn]; int s = 0, r; // Section H.2.2: decode the sample difference //was HUFF_DECODE(s, br_state, dctbl, return mcu_num, 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(mcu_num); } 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(mcu_num); } 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(mcu_num); } get_buffer = br_state.get_buffer; bits_left = br_state.bits_left; } } } if (s != 0) { if (s == 16) { s = 32768; // special case: always output 32768 } else { // normal case: fetch subsequent bits //was CHECK_BIT_BUFFER(br_state, s, return mcu_num); if (bits_left < s) { if (!jpeg_fill_bit_buffer(ref br_state, get_buffer, bits_left, s)) { return(mcu_num); } 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 the sample difference int ind = entropy.output_ptr_index[sampn]; entropy.output_ptr[ind][entropy.output_ptr_ind[ind]++] = (int)s; } // 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; } } return(nMCU); }
static CONSUME_INPUT decompress_data_d_diff(jpeg_decompress cinfo, byte[][][] output_buf, int[] output_buf_ind) { jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef; d_diff_controller diff = (d_diff_controller)losslsd.diff_private; // Loop to process as much as one whole iMCU row for (uint yoffset = diff.MCU_vert_offset; yoffset < diff.MCU_rows_per_iMCU_row; yoffset++) { // Process restart marker if needed; may have to suspend if (cinfo.restart_interval != 0) { if (diff.restart_rows_to_go == 0) { if (!process_restart_d_diff(cinfo)) { return(CONSUME_INPUT.JPEG_SUSPENDED); } } } uint MCU_col_num = diff.MCU_ctr; // index of current MCU within row // Try to fetch an MCU-row (or remaining portion of suspended MCU-row). uint MCU_count = losslsd.entropy_decode_mcus(cinfo, diff.diff_buf, yoffset, MCU_col_num, cinfo.MCUs_per_row - MCU_col_num); if (MCU_count != cinfo.MCUs_per_row - MCU_col_num) { // Suspension forced; update state counters and exit diff.MCU_vert_offset = yoffset; diff.MCU_ctr += MCU_count; return(CONSUME_INPUT.JPEG_SUSPENDED); } // Account for restart interval (no-op if not using restarts) diff.restart_rows_to_go--; // Completed an MCU row, but perhaps not an iMCU row diff.MCU_ctr = 0; } uint last_iMCU_row = cinfo.total_iMCU_rows - 1; // Undifference and scale each scanline of the disassembled MCU-row // separately. We do not process dummy samples at the end of a scanline // or dummy rows at the end of the image. for (int comp = 0; comp < cinfo.comps_in_scan; comp++) { jpeg_component_info compptr = cinfo.cur_comp_info[comp]; int ci = compptr.component_index; int stop = cinfo.input_iMCU_row == last_iMCU_row?compptr.last_row_height:compptr.v_samp_factor; for (int row = 0, prev_row = compptr.v_samp_factor - 1; row < stop; prev_row = row, row++) { losslsd.predict_undifference[ci](cinfo, ci, diff.diff_buf[ci][row], diff.undiff_buf[ci][prev_row], diff.undiff_buf[ci][row], compptr.width_in_blocks); losslsd.scaler_scale(cinfo, diff.undiff_buf[ci][row], output_buf[ci][output_buf_ind[ci] + row], compptr.width_in_blocks); } } // Completed the iMCU row, advance counters for next one. // // NB: output_data will increment output_iMCU_row. // This counter is not needed for the single-pass case // or the input side of the multi-pass case. if (++(cinfo.input_iMCU_row) < cinfo.total_iMCU_rows) { start_iMCU_row_d_diff(cinfo); return(CONSUME_INPUT.JPEG_ROW_COMPLETED); } // Completed the scan cinfo.inputctl.finish_input_pass(cinfo); return(CONSUME_INPUT.JPEG_SCAN_COMPLETED); }