// Process some data. // This handles the simple case where no context is required. static void process_data_simple_d_main(jpeg_decompress cinfo, byte[][] output_buf, ref uint out_row_ctr, uint out_rows_avail) { my_d_main_controller main = (my_d_main_controller)cinfo.main; uint rowgroups_avail; // Read input data if we haven't filled the main buffer yet if (!main.buffer_full) { if (cinfo.coef.decompress_data(cinfo, main.buffer) == CONSUME_INPUT.JPEG_SUSPENDED) { return; // suspension forced, can do nothing more } main.buffer_full = true; // OK, we have an iMCU row to work with } // There are always min_codec_data_unit row groups in an iMCU row. rowgroups_avail = (uint)cinfo.min_DCT_scaled_size; // Note: at the bottom of the image, we may pass extra garbage row groups // to the postprocessor. The postprocessor has to check for bottom // of image anyway (at row resolution), so no point in us doing it too. // Feed the postprocessor cinfo.post.post_process_data(cinfo, main.buffer, ref main.rowgroup_ctr, rowgroups_avail, output_buf, 0, ref out_row_ctr, out_rows_avail); // Has postprocessor consumed all the data yet? If so, mark buffer empty if (main.rowgroup_ctr >= rowgroups_avail) { main.buffer_full = false; main.rowgroup_ctr = 0; } }
const int CTX_POSTPONED_ROW = 2; // feeding postponed row group #endif // Initialize for a processing pass. static void start_pass_d_main(jpeg_decompress cinfo, J_BUF_MODE pass_mode) { my_d_main_controller main = (my_d_main_controller)cinfo.main; switch (pass_mode) { case J_BUF_MODE.JBUF_PASS_THRU: #if UPSCALING_CONTEXT if (cinfo.upsample.need_context_rows) { main.process_data = process_data_context_d_main; main.context_state = CTX_PREPARE_FOR_IMCU; main.iMCU_row_ctr = 0; } else #endif main.process_data = process_data_simple_d_main; // Simple case with no context needed main.buffer_full = false; // Mark buffer empty main.rowgroup_ctr = 0; break; #if QUANT_2PASS_SUPPORTED case J_BUF_MODE.JBUF_CRANK_DEST: main.process_data = process_data_crank_post_d_main; break; // For last pass of 2-pass quantization, just crank the postprocessor #endif default: ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_BUFFER_MODE); break; } }
// Initialize main buffer controller. public static void jinit_d_main_controller(jpeg_decompress cinfo, bool need_full_buffer) { my_d_main_controller main = null; try { main = new my_d_main_controller(); } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } cinfo.main = main; main.start_pass = start_pass_d_main; if (need_full_buffer) { ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_BUFFER_MODE); // shouldn't happen } // Allocate the workspace. // ngroups is the number of row groups we need. int ngroups = cinfo.min_DCT_scaled_size; #if UPSCALING_CONTEXT if (cinfo.upsample.need_context_rows) { if (cinfo.min_DCT_scaled_size < 2) { ERREXIT(cinfo, J_MESSAGE_CODE.JERR_NOTIMPL); // unsupported, see comments above } ngroups = cinfo.min_DCT_scaled_size + 2; } #endif for (int ci = 0; ci < cinfo.num_components; ci++) { jpeg_component_info compptr = cinfo.comp_info[ci]; compptr.notFirst = false; int rgroup = (compptr.v_samp_factor * (int)compptr.DCT_scaled_size) / cinfo.min_DCT_scaled_size; // height of a row group of component main.buffer[ci] = alloc_sarray(cinfo, compptr.width_in_blocks * compptr.DCT_scaled_size, (uint)(rgroup * ngroups)); } }
// Process some data. // This handles the case where context rows must be provided. static void process_data_context_d_main(jpeg_decompress cinfo, byte[][] output_buf, ref uint out_row_ctr, uint out_rows_avail) { my_d_main_controller main = (my_d_main_controller)cinfo.main; // Read input data if we haven't filled the main buffer yet if (!main.buffer_full) { if (cinfo.coef.decompress_data(cinfo, main.buffer) == CONSUME_INPUT.JPEG_SUSPENDED) { return; // suspension forced, can do nothing more } main.buffer_full = true; // OK, we have an iMCU row to work with main.iMCU_row_ctr++; // count rows received } // Postprocessor typically will not swallow all the input data it is handed // in one call (due to filling the output buffer first). Must be prepared // to exit and restart. This switch lets us keep track of how far we got. // Note that each case falls through to the next on successful completion. switch (main.context_state) { case CTX_POSTPONED_ROW: // Call postprocessor using previously set pointers for postponed row cinfo.post.post_process_data(cinfo, main.buffer, ref main.rowgroup_ctr, main.rowgroups_avail, output_buf, 0, ref out_row_ctr, out_rows_avail); if (main.rowgroup_ctr < main.rowgroups_avail) { return; // Need to suspend } main.context_state = CTX_PREPARE_FOR_IMCU; if (out_row_ctr >= out_rows_avail) { return; // Postprocessor exactly filled output buf } goto case CTX_PREPARE_FOR_IMCU; // FALLTHROUGH case CTX_PREPARE_FOR_IMCU: // Prepare to process first M-1 row groups of this iMCU row main.rowgroup_ctr = 0; main.rowgroups_avail = (uint)(cinfo.min_DCT_scaled_size - 1); // Check for bottom of image: if so, tweak pointers to "duplicate" // the last sample row, and adjust rowgroups_avail to ignore padding rows. if (main.iMCU_row_ctr == cinfo.total_iMCU_rows) { for (int ci = 0; ci < cinfo.num_components; ci++) { jpeg_component_info compptr = cinfo.comp_info[ci]; // Count sample rows in one iMCU row and in one row group int iMCUheight = compptr.v_samp_factor * (int)compptr.DCT_scaled_size; int rgroup = iMCUheight / cinfo.min_DCT_scaled_size; // Count nondummy sample rows remaining for this component int rows_left = (int)(compptr.downsampled_height % (uint)iMCUheight); if (rows_left == 0) { rows_left = iMCUheight; } // Count nondummy row groups. Should get same answer for each component, // so we need only do it once. if (ci == 0) { main.rowgroups_avail = (uint)((rows_left - 1) / rgroup + 1); } if (!compptr.doContext) { continue; } byte[][] rows = main.buffer[ci]; int l = rows.Length - 1; for (int i = 0; i < rgroup; i++) { rows[l - rgroup * 2].CopyTo(rows[rows.Length - rgroup * 2 + i], 0); } } } main.context_state = CTX_PROCESS_IMCU; goto case CTX_PROCESS_IMCU; // FALLTHROUGH case CTX_PROCESS_IMCU: // Call postprocessor using previously set pointers cinfo.post.post_process_data(cinfo, main.buffer, ref main.rowgroup_ctr, main.rowgroups_avail, output_buf, 0, ref out_row_ctr, out_rows_avail); if (main.rowgroup_ctr < main.rowgroups_avail) { return; // Need to suspend } for (int ci = 0; ci < cinfo.num_components; ci++) { jpeg_component_info compptr = cinfo.comp_info[ci]; // Count sample rows in one iMCU row and in one row group int iMCUheight = compptr.v_samp_factor * (int)compptr.DCT_scaled_size; int rgroup = iMCUheight / cinfo.min_DCT_scaled_size; byte[][] rows = main.buffer[ci]; int l = rows.Length - 1; for (int i = 0; i < rgroup * 2; i++) { byte[] tmp = rows[l - i - rgroup * 2]; rows[l - i - rgroup * 2] = rows[l - i]; rows[l - i] = tmp; } } // Prepare to load new iMCU row using other xbuffer list //main.whichptr^=1; // 0=>1 or 1=>0 main.buffer_full = false; // Still need to process last row group of this iMCU row, // which is saved at index M+1 of the other xbuffer main.rowgroup_ctr = (uint)(cinfo.min_DCT_scaled_size + 1); main.rowgroups_avail = (uint)(cinfo.min_DCT_scaled_size + 2); main.context_state = CTX_POSTPONED_ROW; break; } }
// Initialize main buffer controller. public static void jinit_d_main_controller(jpeg_decompress cinfo, bool need_full_buffer) { my_d_main_controller main=null; try { main=new my_d_main_controller(); } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } cinfo.main=main; main.start_pass=start_pass_d_main; if(need_full_buffer) ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_BUFFER_MODE); // shouldn't happen // Allocate the workspace. // ngroups is the number of row groups we need. int ngroups=cinfo.min_DCT_scaled_size; #if UPSCALING_CONTEXT if(cinfo.upsample.need_context_rows) { if(cinfo.min_DCT_scaled_size<2) ERREXIT(cinfo, J_MESSAGE_CODE.JERR_NOTIMPL); // unsupported, see comments above ngroups=cinfo.min_DCT_scaled_size+2; } #endif for(int ci=0; ci<cinfo.num_components; ci++) { jpeg_component_info compptr=cinfo.comp_info[ci]; compptr.notFirst=false; int rgroup=(compptr.v_samp_factor*(int)compptr.DCT_scaled_size)/cinfo.min_DCT_scaled_size; // height of a row group of component main.buffer[ci]=alloc_sarray(cinfo, compptr.width_in_blocks*compptr.DCT_scaled_size, (uint)(rgroup*ngroups)); } }