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