/// <summary> /// Reset within-iMCU-row counters for a new row (input side) /// </summary> private void start_iMCU_row() { /* 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 (m_cinfo.m_comps_in_scan > 1) { m_MCU_rows_per_iMCU_row = 1; } else { jpeg_component_info componentInfo = m_cinfo.Comp_info[m_cinfo.m_cur_comp_info[0]]; if (m_cinfo.m_input_iMCU_row < (m_cinfo.m_total_iMCU_rows - 1)) { m_MCU_rows_per_iMCU_row = componentInfo.V_samp_factor; } else { m_MCU_rows_per_iMCU_row = componentInfo.last_row_height; } } m_MCU_ctr = 0; m_MCU_vert_offset = 0; }
// Save away a copy of the Q-table referenced by each component present // in the current scan, unless already saved during a prior scan. // // In a multiple-scan JPEG file, the encoder could assign different components // the same Q-table slot number, but change table definitions between scans // so that each component uses a different Q-table. (The IJG encoder is not // currently capable of doing this, but other encoders might.) Since we want // to be able to dequantize all the components at the end of the file, this // means that we have to save away the table actually used for each component. // We do this by copying the table at the start of the first scan containing // the component. // The JPEG spec prohibits the encoder from changing the contents of a Q-table // slot between scans of a component using that slot. If the encoder does so // anyway, this decoder will simply use the Q-table values that were current // at the start of the first scan for the component. // // The decompressor output side looks only at the saved quant tables, // not at the current Q-table slots. static void latch_quant_tables_lossy(jpeg_decompress cinfo) { for (int ci = 0; ci < cinfo.comps_in_scan; ci++) { jpeg_component_info compptr = cinfo.cur_comp_info[ci]; // No work if we already saved Q-table for this component if (compptr.quant_table != null) { continue; } // Make sure specified quantization table is present int qtblno = compptr.quant_tbl_no; if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || cinfo.quant_tbl_ptrs[qtblno] == null) { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_NO_QUANT_TABLE, qtblno); } // OK, save away the quantization table JQUANT_TBL qtbl = new JQUANT_TBL(); cinfo.quant_tbl_ptrs[qtblno].quantval.CopyTo(qtbl.quantval, 0); qtbl.sent_table = cinfo.quant_tbl_ptrs[qtblno].sent_table; compptr.quant_table = qtbl; } }
/// <summary> /// Downsample pixel values of a single component. /// This version handles the standard case of 2:1 horizontal and 2:1 vertical, /// without smoothing. /// </summary> private void h2v2_downsample(int componentIndex, byte[][] input_data, int startInputRow, byte[][] output_data, int startOutRow) { /* Expand input data enough to let all the output samples be generated * by the standard loop. Special-casing padded output would be more * efficient. */ jpeg_component_info compptr = m_cinfo.Component_info[componentIndex]; int output_cols = compptr.Width_in_blocks * compptr.DCT_h_scaled_size; expand_right_edge(input_data, startInputRow, m_cinfo.m_max_v_samp_factor, m_cinfo.m_image_width, output_cols * 2); int inrow = 0; int outrow = 0; while (inrow < m_cinfo.m_max_v_samp_factor) { /* bias = 1,2,1,2,... for successive samples */ int bias = 1; int inputColumn = 0; for (int outcol = 0; outcol < output_cols; outcol++) { output_data[startOutRow + outrow][outcol] = (byte)(( (int)input_data[startInputRow + inrow][inputColumn] + (int)input_data[startInputRow + inrow][inputColumn + 1] + (int)input_data[startInputRow + inrow + 1][inputColumn] + (int)input_data[startInputRow + inrow + 1][inputColumn + 1] + bias) >> 2); bias ^= 3; /* 1=>2, 2=>1 */ inputColumn += 2; } inrow += 2; outrow++; } }
// 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; } }
////////////////////////////////////////////////////////////////////////// // Routines to write specific marker types. // /// <summary> /// Emit a SOS marker /// </summary> private void emit_sos() { emit_marker(JPEG_MARKER.SOS); emit_2bytes(2 * m_cinfo.m_comps_in_scan + 2 + 1 + 3); /* length */ emit_byte(m_cinfo.m_comps_in_scan); for (int i = 0; i < m_cinfo.m_comps_in_scan; i++) { int componentIndex = m_cinfo.m_cur_comp_info[i]; jpeg_component_info compptr = m_cinfo.Component_info[componentIndex]; emit_byte(compptr.Component_id); /* We emit 0 for unused field(s); this is recommended by the P&M text * but does not seem to be specified in the standard. */ /* DC needs no table for refinement scan */ int td = (m_cinfo.m_Ss == 0 && m_cinfo.m_Ah == 0) ? compptr.Dc_tbl_no : 0; /* AC needs no table when not present */ int ta = (m_cinfo.m_Se != 0) ? compptr.Ac_tbl_no : 0; emit_byte((td << 4) + ta); } emit_byte(m_cinfo.m_Ss); emit_byte(m_cinfo.m_Se); emit_byte((m_cinfo.m_Ah << 4) + m_cinfo.m_Al); }
/// <summary> /// Emit a SOF marker /// </summary> private void emit_sof(JPEG_MARKER code) { emit_marker(code); emit_2bytes(3 * m_cinfo.m_num_components + 2 + 5 + 1); /* length */ /* Make sure image isn't bigger than SOF field can handle */ if (m_cinfo.m_image_height > 65535 || m_cinfo.m_image_width > 65535) { m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_IMAGE_TOO_BIG, 65535); } emit_byte(m_cinfo.m_data_precision); emit_2bytes(m_cinfo.m_image_height); emit_2bytes(m_cinfo.m_image_width); emit_byte(m_cinfo.m_num_components); for (int ci = 0; ci < m_cinfo.m_num_components; ci++) { jpeg_component_info componentInfo = m_cinfo.Component_info[ci]; emit_byte(componentInfo.Component_id); emit_byte((componentInfo.H_samp_factor << 4) + componentInfo.V_samp_factor); emit_byte(componentInfo.Quant_tbl_no); } }
/// <summary> /// Save away a copy of the Q-table referenced by each component present /// in the current scan, unless already saved during a prior scan. /// /// In a multiple-scan JPEG file, the encoder could assign different components /// the same Q-table slot number, but change table definitions between scans /// so that each component uses a different Q-table. (The IJG encoder is not /// currently capable of doing this, but other encoders might.) Since we want /// to be able to dequantize all the components at the end of the file, this /// means that we have to save away the table actually used for each component. /// We do this by copying the table at the start of the first scan containing /// the component. /// The JPEG spec prohibits the encoder from changing the contents of a Q-table /// slot between scans of a component using that slot. If the encoder does so /// anyway, this decoder will simply use the Q-table values that were current /// at the start of the first scan for the component. /// /// The decompressor output side looks only at the saved quant tables, /// not at the current Q-table slots. /// </summary> private void latch_quant_tables() { for (int ci = 0; ci < m_cinfo.m_comps_in_scan; ci++) { jpeg_component_info componentInfo = m_cinfo.Comp_info[m_cinfo.m_cur_comp_info[ci]]; /* No work if we already saved Q-table for this component */ if (componentInfo.quant_table != null) { continue; } /* Make sure specified quantization table is present */ int qtblno = componentInfo.Quant_tbl_no; if (qtblno < 0 || qtblno >= JpegConstants.NUM_QUANT_TBLS || m_cinfo.m_quant_tbl_ptrs[qtblno] == null) { m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_NO_QUANT_TABLE, qtblno); } /* OK, save away the quantization table */ JQUANT_TBL qtbl = new JQUANT_TBL(); Buffer.BlockCopy(m_cinfo.m_quant_tbl_ptrs[qtblno].quantval, 0, qtbl.quantval, 0, qtbl.quantval.Length * sizeof(short)); qtbl.Sent_table = m_cinfo.m_quant_tbl_ptrs[qtblno].Sent_table; componentInfo.quant_table = qtbl; m_cinfo.Comp_info[m_cinfo.m_cur_comp_info[ci]] = componentInfo; } }
// Process some data in subsequent passes of a multi-pass case. // We process the equivalent of one fully interleaved MCU row ("iMCU" row) // per call, ie, v_samp_factor block rows for each component in the scan. // The data is obtained from the arrays and fed to the entropy coder. // Returns true if the iMCU row is completed, false if suspended. // // NB: input_buf is ignored; it is likely to be a null pointer. static bool compress_output_coef(jpeg_compress cinfo, byte[][][] input_buf) { jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef; c_coef_controller coef = (c_coef_controller)lossyc.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. // NB: during first pass, this is safe only because the buffers will // already be aligned properly, so jmemmgr.cs won't need to do any I/O. 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)coef.iMCU_row_num * compptr.v_samp_factor; } // 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++) { // 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 write the MCU. if (!lossyc.entropy_encode_mcu(cinfo, coef.MCU_buffer)) { // Suspension forced; update state counters and exit coef.MCU_vert_offset = yoffset; coef.mcu_ctr = MCU_col_num; return(false); } } // Completed an MCU row, but perhaps not an iMCU row coef.mcu_ctr = 0; } // Completed the iMCU row, advance counters for next one coef.iMCU_row_num++; start_iMCU_row_c_coef(cinfo); return(true); }
// Trial-encode one MCU's worth of Huffman-compressed coefficients. // No data is actually output, so no suspension return is possible. static bool encode_mcu_gather_sq(jpeg_compress cinfo, short[][] MCU_data) { jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef; shuff_entropy_encoder entropy = (shuff_entropy_encoder)lossyc.entropy_private; // Take care of restart intervals if needed if (cinfo.restart_interval != 0) { if (entropy.restarts_to_go == 0) { // Re-initialize DC predictions to 0 for (int ci = 0; ci < cinfo.comps_in_scan; ci++) { entropy.saved.last_dc_val[ci] = 0; } // Update restart state entropy.restarts_to_go = cinfo.restart_interval; } entropy.restarts_to_go--; } for (int blkn = 0; blkn < cinfo.block_in_MCU; blkn++) { int ci = cinfo.MCU_membership[blkn]; jpeg_component_info compptr = cinfo.cur_comp_info[ci]; htest_one_block_sq(cinfo, MCU_data[blkn], entropy.saved.last_dc_val[ci], entropy.dc_count_ptrs[compptr.dc_tbl_no], entropy.ac_count_ptrs[compptr.ac_tbl_no]); entropy.saved.last_dc_val[ci] = MCU_data[blkn][0]; } return(true); }
// Emit a SOS marker static void emit_sos(jpeg_compress cinfo) { emit_marker(cinfo, JPEG_MARKER.M_SOS); emit_2bytes(cinfo, 2*cinfo.comps_in_scan+2+1+3); // length emit_byte(cinfo, cinfo.comps_in_scan); for(int i=0; i<cinfo.comps_in_scan; i++) { jpeg_component_info compptr=cinfo.cur_comp_info[i]; emit_byte(cinfo, compptr.component_id); int td=compptr.dc_tbl_no; int ta=compptr.ac_tbl_no; if(cinfo.process==J_CODEC_PROCESS.JPROC_PROGRESSIVE) { // Progressive mode: only DC or only AC tables are used in one scan; // furthermore, Huffman coding of DC refinement uses no table at all. // We emit 0 for unused field(s); this is recommended by the P&M text // but does not seem to be specified in the standard. if(cinfo.Ss==0) { ta=0; // DC scan if(cinfo.Ah!=0&&!cinfo.arith_code) td=0; // no DC table either } else td=0; // AC scan } emit_byte(cinfo, (td<<4)+ta); } emit_byte(cinfo, cinfo.Ss); emit_byte(cinfo, cinfo.Se); emit_byte(cinfo, (cinfo.Ah<<4)+cinfo.Al); }
/// <summary> /// Process some data in subsequent passes of a multi-pass case. /// We process the equivalent of one fully interleaved MCU row ("iMCU" row) /// per call, ie, v_samp_factor block rows for each component in the scan. /// The data is obtained from the virtual arrays and fed to the entropy coder. /// Returns true if the iMCU row is completed, false if suspended. /// </summary> private bool compressOutput() { /* Align the virtual buffers for the components used in this scan. */ JBLOCK[][][] buffer = new JBLOCK[JpegConstants.MAX_COMPS_IN_SCAN][][]; for (int ci = 0; ci < m_cinfo.m_comps_in_scan; ci++) { jpeg_component_info componentInfo = m_cinfo.Component_info[m_cinfo.m_cur_comp_info[ci]]; buffer[ci] = m_whole_image[componentInfo.Component_index].Access( m_iMCU_row_num * componentInfo.V_samp_factor, componentInfo.V_samp_factor); } /* Loop to process one whole iMCU row */ for (int yoffset = m_MCU_vert_offset; yoffset < m_MCU_rows_per_iMCU_row; yoffset++) { for (int MCU_col_num = m_mcu_ctr; MCU_col_num < m_cinfo.m_MCUs_per_row; MCU_col_num++) { /* 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 < m_cinfo.m_comps_in_scan; ci++) { jpeg_component_info componentInfo = m_cinfo.Component_info[m_cinfo.m_cur_comp_info[ci]]; int start_col = MCU_col_num * componentInfo.MCU_width; for (int yindex = 0; yindex < componentInfo.MCU_height; yindex++) { for (int xindex = 0; xindex < componentInfo.MCU_width; xindex++) { int bufLength = buffer[ci][yindex + yoffset].Length; int start = start_col + xindex; m_MCU_buffer[blkn] = new JBLOCK[bufLength - start]; for (int j = start; j < bufLength; j++) { m_MCU_buffer[blkn][j - start] = buffer[ci][yindex + yoffset][j]; } blkn++; } } } /* Try to write the MCU. */ if (!m_cinfo.m_entropy.encode_mcu(m_MCU_buffer)) { /* Suspension forced; update state counters and exit */ m_MCU_vert_offset = yoffset; m_mcu_ctr = MCU_col_num; return(false); } } /* Completed an MCU row, but perhaps not an iMCU row */ m_mcu_ctr = 0; } /* Completed the iMCU row, advance counters for next one */ m_iMCU_row_num++; start_iMCU_row(); return(true); }
// 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; }
/// <summary> /// Initialize for a Huffman-compressed scan. /// </summary> public override void start_pass() { /* 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 (m_cinfo.m_Ss != 0 || m_cinfo.m_Se != JpegConstants.DCTSIZE2 - 1 || m_cinfo.m_Ah != 0 || m_cinfo.m_Al != 0) { m_cinfo.WARNMS(J_MESSAGE_CODE.JWRN_NOT_SEQUENTIAL); } for (int ci = 0; ci < m_cinfo.m_comps_in_scan; ci++) { jpeg_component_info componentInfo = m_cinfo.Comp_info[m_cinfo.m_cur_comp_info[ci]]; int dctbl = componentInfo.Dc_tbl_no; int actbl = componentInfo.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(true, dctbl, ref m_dc_derived_tbls[dctbl]); jpeg_make_d_derived_tbl(false, actbl, ref m_ac_derived_tbls[actbl]); /* Initialize DC predictions to 0 */ m_saved.last_dc_val[ci] = 0; } /* Precalculate decoding info for each block in an MCU of this scan */ for (int blkn = 0; blkn < m_cinfo.m_blocks_in_MCU; blkn++) { int ci = m_cinfo.m_MCU_membership[blkn]; jpeg_component_info componentInfo = m_cinfo.Comp_info[m_cinfo.m_cur_comp_info[ci]]; /* Precalculate which table to use for each block */ m_dc_cur_tbls[blkn] = m_dc_derived_tbls[componentInfo.Dc_tbl_no]; m_ac_cur_tbls[blkn] = m_ac_derived_tbls[componentInfo.Ac_tbl_no]; /* Decide whether we really care about the coefficient values */ if (componentInfo.component_needed) { m_dc_needed[blkn] = true; /* we don't need the ACs if producing a 1/8th-size image */ m_ac_needed[blkn] = (componentInfo.DCT_scaled_size > 1); } else { m_dc_needed[blkn] = m_ac_needed[blkn] = false; } } /* Initialize bitread state variables */ m_bitstate.bits_left = 0; m_bitstate.get_buffer = 0; m_insufficient_data = false; /* Initialize restart counter */ m_restarts_to_go = m_cinfo.m_restart_interval; }
/// <summary> /// Downsample pixel values of a single component. /// This version handles the special case of a full-size component, /// without smoothing. /// </summary> private void fullsize_downsample(int componentIndex, byte[][] input_data, int startInputRow, byte[][] output_data, int startOutRow) { /* Copy the data */ JpegUtils.jcopy_sample_rows(input_data, startInputRow, output_data, startOutRow, m_cinfo.m_max_v_samp_factor, m_cinfo.m_image_width); /* Edge-expand */ jpeg_component_info compptr = m_cinfo.Component_info[componentIndex]; expand_right_edge(output_data, startOutRow, m_cinfo.m_max_v_samp_factor, m_cinfo.m_image_width, compptr.Width_in_blocks * compptr.DCT_h_scaled_size); }
// Write scan header. // This consists of DHT or DAC markers, optional DRI, and SOS. // Compressed data will be written following the SOS. static void write_scan_header(jpeg_compress cinfo) { if(cinfo.arith_code) { // Emit arith conditioning info. We may have some duplication // if the file has multiple scans, but it's so small it's hardly // worth worrying about. emit_dac(cinfo); } else { // Emit Huffman tables. // Note that emit_dht() suppresses any duplicate tables. for(int i=0; i<cinfo.comps_in_scan; i++) { jpeg_component_info compptr=cinfo.cur_comp_info[i]; if(cinfo.process==J_CODEC_PROCESS.JPROC_PROGRESSIVE) { // Progressive mode: only DC or only AC tables are used in one scan if(cinfo.Ss==0) { if(cinfo.Ah==0) emit_dht(cinfo, compptr.dc_tbl_no, false); // DC needs no table for refinement scan } else { emit_dht(cinfo, compptr.ac_tbl_no, true); } } else if(cinfo.process==J_CODEC_PROCESS.JPROC_LOSSLESS) { // Lossless mode: only DC tables are used emit_dht(cinfo, compptr.dc_tbl_no, false); } else { // Sequential mode: need both DC and AC tables emit_dht(cinfo, compptr.dc_tbl_no, false); emit_dht(cinfo, compptr.ac_tbl_no, true); } } } my_marker_writer marker=(my_marker_writer)cinfo.marker; // Emit DRI if required --- note that DRI value could change for each scan. // We avoid wasting space with unnecessary DRIs, however. if(cinfo.restart_interval!=marker.last_restart_interval) { emit_dri(cinfo); marker.last_restart_interval=cinfo.restart_interval; } emit_sos(cinfo); }
/// <summary> /// Process some data in the simple no-context case. /// /// Preprocessor output data is counted in "row groups". A row group /// is defined to be v_samp_factor sample rows of each component. /// Downsampling will produce this much data from each max_v_samp_factor /// input rows. /// </summary> private void pre_process_WithoutContext(byte[][] input_buf, ref int in_row_ctr, int in_rows_avail, byte[][][] output_buf, ref int out_row_group_ctr, int out_row_groups_avail) { while (in_row_ctr < in_rows_avail && out_row_group_ctr < out_row_groups_avail) { /* Do color conversion to fill the conversion buffer. */ int inrows = in_rows_avail - in_row_ctr; int numrows = m_cinfo.m_max_v_samp_factor - m_next_buf_row; numrows = Math.Min(numrows, inrows); m_cinfo.m_cconvert.color_convert(input_buf, in_row_ctr, m_color_buf, m_colorBufRowsOffset + m_next_buf_row, numrows); in_row_ctr += numrows; m_next_buf_row += numrows; m_rows_to_go -= numrows; /* If at bottom of image, pad to fill the conversion buffer. */ if (m_rows_to_go == 0 && m_next_buf_row < m_cinfo.m_max_v_samp_factor) { for (int ci = 0; ci < m_cinfo.m_num_components; ci++) { expand_bottom_edge(m_color_buf[ci], m_colorBufRowsOffset, m_cinfo.m_image_width, m_next_buf_row, m_cinfo.m_max_v_samp_factor); } m_next_buf_row = m_cinfo.m_max_v_samp_factor; } /* If we've filled the conversion buffer, empty it. */ if (m_next_buf_row == m_cinfo.m_max_v_samp_factor) { m_cinfo.m_downsample.downsample(m_color_buf, m_colorBufRowsOffset, output_buf, out_row_group_ctr); m_next_buf_row = 0; out_row_group_ctr++; } /* If at bottom of image, pad the output to a full iMCU height. * Note we assume the caller is providing a one-iMCU-height output buffer! */ if (m_rows_to_go == 0 && out_row_group_ctr < out_row_groups_avail) { for (int ci = 0; ci < m_cinfo.m_num_components; ci++) { jpeg_component_info componentInfo = m_cinfo.Component_info[ci]; numrows = (componentInfo.V_samp_factor * componentInfo.DCT_v_scaled_size) / m_cinfo.min_DCT_v_scaled_size; expand_bottom_edge(output_buf[ci], 0, componentInfo.Width_in_blocks * componentInfo.DCT_h_scaled_size, out_row_group_ctr * numrows, out_row_groups_avail * numrows); } out_row_group_ctr = out_row_groups_avail; break; /* can exit outer loop without test */ } } }
/// <summary> /// Finish up a statistics-gathering pass and create the new Huffman tables. /// </summary> private void finish_pass_gather_phuff() { /* Flush out buffered data (all we care about is counting the EOB symbol) */ emit_eobrun(); /* It's important not to apply jpeg_gen_optimal_table more than once * per table, because it clobbers the input frequency counts! */ bool[] did = new bool [JpegConstants.NUM_HUFF_TBLS]; bool is_DC_band = (m_cinfo.m_Ss == 0); for (int ci = 0; ci < m_cinfo.m_comps_in_scan; ci++) { jpeg_component_info componentInfo = m_cinfo.Component_info[m_cinfo.m_cur_comp_info[ci]]; int tbl = componentInfo.Ac_tbl_no; if (is_DC_band) { if (m_cinfo.m_Ah != 0) /* DC refinement needs no table */ { continue; } tbl = componentInfo.Dc_tbl_no; } if (!did[tbl]) { JHUFF_TBL htblptr = null; if (is_DC_band) { if (m_cinfo.m_dc_huff_tbl_ptrs[tbl] == null) { m_cinfo.m_dc_huff_tbl_ptrs[tbl] = new JHUFF_TBL(); } htblptr = m_cinfo.m_dc_huff_tbl_ptrs[tbl]; } else { if (m_cinfo.m_ac_huff_tbl_ptrs[tbl] == null) { m_cinfo.m_ac_huff_tbl_ptrs[tbl] = new JHUFF_TBL(); } htblptr = m_cinfo.m_ac_huff_tbl_ptrs[tbl]; } jpeg_gen_optimal_table(htblptr, m_count_ptrs[tbl]); did[tbl] = true; } } }
// Finish up a statistics-gathering pass and create the new Huffman tables. static void finish_pass_gather_phuff(jpeg_compress cinfo) { jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef; phuff_entropy_encoder entropy = (phuff_entropy_encoder)lossyc.entropy_private; // Flush out buffered data (all we care about is counting the EOB symbol) emit_eobrun(entropy); bool is_DC_band = (cinfo.Ss == 0); // It's important not to apply jpeg_gen_optimal_table more than once // per table, because it clobbers the input frequency counts! bool[] did = new bool[NUM_HUFF_TBLS]; for (int ci = 0; ci < cinfo.comps_in_scan; ci++) { jpeg_component_info compptr = cinfo.cur_comp_info[ci]; int tbl; if (is_DC_band) { if (cinfo.Ah != 0) { continue; // DC refinement needs no table } tbl = compptr.dc_tbl_no; } else { tbl = compptr.ac_tbl_no; } if (!did[tbl]) { if (is_DC_band) { if (cinfo.dc_huff_tbl_ptrs[tbl] == null) { cinfo.dc_huff_tbl_ptrs[tbl] = jpeg_alloc_huff_table(cinfo); } jpeg_gen_optimal_table(cinfo, cinfo.dc_huff_tbl_ptrs[tbl], entropy.count_ptrs[tbl]); } else { if (cinfo.ac_huff_tbl_ptrs[tbl] == null) { cinfo.ac_huff_tbl_ptrs[tbl] = jpeg_alloc_huff_table(cinfo); } jpeg_gen_optimal_table(cinfo, cinfo.ac_huff_tbl_ptrs[tbl], entropy.count_ptrs[tbl]); } did[tbl] = true; } } }
// 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 } }
static void jinit_c_coef_controller(jpeg_compress cinfo, bool need_full_buffer) { jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef; c_coef_controller coef = null; try { coef = new c_coef_controller(); } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } lossyc.coef_private = coef; lossyc.coef_start_pass = start_pass_coef; // Create the coefficient buffer. if (need_full_buffer) { #if FULL_COEF_BUFFER_SUPPORTED // Allocate a full-image array for each component, // padded to a multiple of samp_factor DCT blocks in each direction. for (int ci = 0; ci < cinfo.num_components; ci++) { jpeg_component_info compptr = cinfo.comp_info[ci]; coef.whole_image[ci] = alloc_barray(cinfo, (uint)jround_up((int)compptr.width_in_blocks, compptr.h_samp_factor), (uint)jround_up((int)compptr.height_in_blocks, compptr.v_samp_factor)); } #else ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_BUFFER_MODE); #endif } else { // We only need a single-MCU buffer. try { for (int i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) { coef.MCU_buffer[i] = new short[DCTSIZE2]; } } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } coef.whole_image[0] = null; // flag for no arrays } }
// This version is used for floating-point DCT implementations. static void forward_DCT_float(jpeg_compress cinfo, jpeg_component_info compptr, byte[][] sample_data, short[][] coef_blocks, int coef_offset, uint start_row, uint start_col, uint num_blocks) { // This routine is heavily used, so it's worth coding it tightly jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef; fdct_controller fdct = (fdct_controller)lossyc.fdct_private; float_DCT_method_ptr do_dct = fdct.do_float_dct; double[] divisors = fdct.float_divisors[compptr.quant_tbl_no]; double[] workspace = new double[DCTSIZE2]; // work area for FDCT subroutine for (int bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) { // Load data into workspace, applying unsigned->signed conversion int wsptr = 0; for (int elemr = 0; elemr < DCTSIZE; elemr++) { byte[] elem = sample_data[start_row + elemr]; uint eptr = start_col; // unroll the inner loop workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; } // Perform the DCT do_dct(workspace); // Quantize/descale the coefficients, and store into coef_blocks[] //old short[] output_ptr=coef_blocks[coef_offset][bi]; short[] output_ptr = coef_blocks[coef_offset + bi]; for (int i = 0; i < DCTSIZE2; i++) { // Apply the quantization and scaling factor double temp = workspace[i] * divisors[i]; // Round to nearest integer. // Since C does not specify the direction of rounding for negative // quotients, we have to force the dividend positive for portability. // The maximum coefficient size is +-16K (for 12-bit data), so this // code should work for either 16-bit or 32-bit ints. output_ptr[i] = (short)((int)(temp + 16384.5) - 16384); } } }
public jpeg_c_main_controller(jpeg_compress_struct cinfo) { m_cinfo = cinfo; /* Allocate a strip buffer for each component */ for (int ci = 0; ci < cinfo.m_num_components; ci++) { jpeg_component_info compptr = cinfo.Component_info[ci]; m_buffer[ci] = jpeg_common_struct.AllocJpegSamples( compptr.Width_in_blocks * compptr.DCT_h_scaled_size, compptr.V_samp_factor * compptr.DCT_v_scaled_size); } }
/* Emit a DAC marker */ /* Since the useful info is so small, we want to emit all the tables in */ /* one DAC marker. Therefore this routine does its own scan of the table. */ private void emit_dac() { byte[] dc_in_use = new byte[JpegConstants.NUM_ARITH_TBLS]; byte[] ac_in_use = new byte[JpegConstants.NUM_ARITH_TBLS]; for (int i = 0; i < m_cinfo.m_comps_in_scan; i++) { jpeg_component_info compptr = m_cinfo.Component_info[m_cinfo.m_cur_comp_info[i]]; /* DC needs no table for refinement scan */ if (m_cinfo.m_Ss == 0 && m_cinfo.m_Ah == 0) { dc_in_use[compptr.Dc_tbl_no] = 1; } /* AC needs no table when not present */ if (m_cinfo.m_Se != 0) { ac_in_use[compptr.Ac_tbl_no] = 1; } } int length = 0; for (int i = 0; i < JpegConstants.NUM_ARITH_TBLS; i++) { length += dc_in_use[i] + ac_in_use[i]; } if (length != 0) { emit_marker(JPEG_MARKER.DAC); emit_2bytes(length * 2 + 2); for (int i = 0; i < JpegConstants.NUM_ARITH_TBLS; i++) { if (dc_in_use[i] != 0) { emit_byte(i); emit_byte(m_cinfo.arith_dc_L[i] + (m_cinfo.arith_dc_U[i] << 4)); } if (ac_in_use[i] != 0) { emit_byte(i + 0x10); emit_byte(m_cinfo.arith_ac_K[i]); } } } }
/// <summary> /// Write scan header. /// This consists of DHT or DAC markers, optional DRI, and SOS. /// Compressed data will be written following the SOS. /// </summary> public void write_scan_header() { if (m_cinfo.arith_code) { /* Emit arith conditioning info. We may have some duplication * if the file has multiple scans, but it's so small it's hardly * worth worrying about. */ emit_dac(); } else { /* Emit Huffman tables. * Note that emit_dht() suppresses any duplicate tables. */ for (int i = 0; i < m_cinfo.m_comps_in_scan; i++) { jpeg_component_info compptr = m_cinfo.Component_info[m_cinfo.m_cur_comp_info[i]]; /* DC needs no table for refinement scan */ if (m_cinfo.m_Ss == 0 && m_cinfo.m_Ah == 0) { emit_dht(compptr.Dc_tbl_no, false); } /* AC needs no table when not present */ if (m_cinfo.m_Se != 0) { emit_dht(compptr.Ac_tbl_no, true); } } /* Emit DRI if required --- note that DRI value could change for each scan. * We avoid wasting space with unnecessary DRIs, however. */ if (m_cinfo.m_restart_interval != m_last_restart_interval) { emit_dri(); m_last_restart_interval = m_cinfo.m_restart_interval; } emit_sos(); } }
// 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)); } }
// Emit a restart marker & resynchronize predictions. static void emit_restart_arith(jpeg_compress cinfo, int restart_num) { arith_entropy_encoder entropy = (arith_entropy_encoder)cinfo.coef; finish_pass_c_arith(cinfo); emit_byte(cinfo, 0xFF); emit_byte(cinfo, JPEG_RST0 + restart_num); for (int ci = 0; ci < cinfo.comps_in_scan; ci++) { jpeg_component_info compptr = cinfo.cur_comp_info[ci]; // Re-initialize statistics areas if (cinfo.process != J_CODEC_PROCESS.JPROC_PROGRESSIVE || (cinfo.Ss == 0 && cinfo.Ah == 0)) { for (int i = 0; i < DC_STAT_BINS; i++) { entropy.dc_stats[compptr.dc_tbl_no][i] = 0; } // Reset DC predictions to 0 entropy.last_dc_val[ci] = 0; entropy.dc_context[ci] = 0; } if (cinfo.process != J_CODEC_PROCESS.JPROC_PROGRESSIVE || cinfo.Ss != 0) { for (int i = 0; i < AC_STAT_BINS; i++) { entropy.ac_stats[compptr.ac_tbl_no][i] = 0; } } } // Reset arithmetic encoding variables entropy.c = 0; entropy.a = 0x10000; entropy.sc = 0; entropy.zc = 0; entropy.ct = 11; entropy.buffer = -1; // empty }
// 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; } } }
// Check for a restart marker & resynchronize decoder. static void process_restart_arith(jpeg_decompress cinfo) { arith_entropy_decoder entropy = (arith_entropy_decoder)cinfo.coef; // Advance past the RSTn marker if (!cinfo.marker.read_restart_marker(cinfo)) { ERREXIT(cinfo, J_MESSAGE_CODE.JERR_CANT_SUSPEND); } for (int ci = 0; ci < cinfo.comps_in_scan; ci++) { jpeg_component_info compptr = cinfo.cur_comp_info[ci]; // Re-initialize statistics areas if (cinfo.process == J_CODEC_PROCESS.JPROC_SEQUENTIAL || (cinfo.Ss == 0 && cinfo.Ah == 0)) { for (int i = 0; i < DC_STAT_BINS; i++) { entropy.dc_stats[compptr.dc_tbl_no][i] = 0; } // Reset DC predictions to 0 entropy.last_dc_val[ci] = 0; entropy.dc_context[ci] = 0; } if (cinfo.process == J_CODEC_PROCESS.JPROC_SEQUENTIAL || cinfo.Ss != 0) { for (int i = 0; i < AC_STAT_BINS; i++) { entropy.ac_stats[compptr.ac_tbl_no][i] = 0; } } } // Reset arithmetic decoding variables entropy.c = 0; entropy.a = 0; entropy.ct = -16; // force reading 2 initial bytes to fill C // Reset restart counter entropy.restarts_to_go = cinfo.restart_interval; }
// Initialize main buffer controller. static void jinit_c_main_controller(jpeg_compress cinfo, bool need_full_buffer) { my_c_main_controller main = null; try { main = new my_c_main_controller(); } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } cinfo.main = main; main.start_pass = start_pass_c_main; // We don't need to create a buffer in raw-data mode. if (cinfo.raw_data_in) { return; } // Create the buffer. It holds downsampled data, so each component // may be of a different size. if (need_full_buffer) { ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_BUFFER_MODE); } else { uint DCT_size = cinfo.DCT_size; // Allocate a strip buffer for each component for (int ci = 0; ci < cinfo.num_components; ci++) { jpeg_component_info compptr = cinfo.comp_info[ci]; main.buffer[ci] = alloc_sarray(cinfo, compptr.width_in_blocks * DCT_size, (uint)(compptr.v_samp_factor * DCT_size)); } } }
/// <summary> /// Downsample pixel values of a single component. /// One row group is processed per call. /// This version handles arbitrary integral sampling ratios, without smoothing. /// Note that this version is not actually used for customary sampling ratios. /// </summary> private void int_downsample(int componentIndex, byte[][] input_data, int startInputRow, byte[][] output_data, int startOutRow) { /* Expand input data enough to let all the output samples be generated * by the standard loop. Special-casing padded output would be more * efficient. */ jpeg_component_info compptr = m_cinfo.Component_info[componentIndex]; int output_cols = compptr.Width_in_blocks * compptr.DCT_h_scaled_size; int h_expand = this.h_expand[compptr.Component_index]; expand_right_edge(input_data, startInputRow, m_cinfo.m_max_v_samp_factor, m_cinfo.m_image_width, output_cols * h_expand); int v_expand = this.v_expand[compptr.Component_index]; int numpix = h_expand * v_expand; int numpix2 = numpix / 2; int inrow = 0; int outrow = 0; while (inrow < m_cinfo.m_max_v_samp_factor) { for (int outcol = 0, outcol_h = 0; outcol < output_cols; outcol++, outcol_h += h_expand) { int outvalue = 0; for (int v = 0; v < v_expand; v++) { for (int h = 0; h < h_expand; h++) { outvalue += input_data[startInputRow + inrow + v][outcol_h + h]; } } output_data[startOutRow + outrow][outcol] = (byte)((outvalue + numpix2) / numpix); } inrow += v_expand; outrow++; } }
// Perform forward DCT on one or more blocks of a component. // // The input samples are taken from the sample_data[] array starting at // position start_row/start_col, and moving to the right for any additional // blocks. The quantized coefficients are returned in coef_blocks[]. // This version is used for integer DCT implementations. static void forward_DCT(jpeg_compress cinfo, jpeg_component_info compptr, byte[][] sample_data, short[][] coef_blocks, int coef_offset, uint start_row, uint start_col, uint num_blocks) { // This routine is heavily used, so it's worth coding it tightly jpeg_lossy_c_codec lossyc=(jpeg_lossy_c_codec)cinfo.coef; fdct_controller fdct=(fdct_controller)lossyc.fdct_private; forward_DCT_method_ptr do_dct=fdct.do_dct; int[] divisors=fdct.divisors[compptr.quant_tbl_no]; int[] workspace=new int[DCTSIZE2]; // work area for FDCT subroutine for(int bi=0; bi<num_blocks; bi++, start_col+=DCTSIZE) { // Load data into workspace, applying unsigned->signed conversion int wsptr=0; for(int elemr=0; elemr<DCTSIZE; elemr++) { byte[] elem=sample_data[start_row+elemr]; uint eptr=start_col; // unroll the inner loop workspace[wsptr++]=elem[eptr++]-CENTERJSAMPLE; workspace[wsptr++]=elem[eptr++]-CENTERJSAMPLE; workspace[wsptr++]=elem[eptr++]-CENTERJSAMPLE; workspace[wsptr++]=elem[eptr++]-CENTERJSAMPLE; workspace[wsptr++]=elem[eptr++]-CENTERJSAMPLE; workspace[wsptr++]=elem[eptr++]-CENTERJSAMPLE; workspace[wsptr++]=elem[eptr++]-CENTERJSAMPLE; workspace[wsptr++]=elem[eptr++]-CENTERJSAMPLE; } // Perform the DCT do_dct(workspace); // Quantize/descale the coefficients, and store into coef_blocks[] //old short[] output_ptr=coef_blocks[coef_offset][bi]; short[] output_ptr=coef_blocks[coef_offset+bi]; for(int i=0; i<DCTSIZE2; i++) { int qval=divisors[i]; int temp=workspace[i]; // Divide the coefficient value by qval, ensuring proper rounding. // Since C does not specify the direction of rounding for negative // quotients, we have to force the dividend positive for portability. if(temp<0) { temp=-temp; temp+=qval>>1; // for rounding temp/=qval; temp=-temp; } else { temp+=qval>>1; // for rounding temp/=qval; } output_ptr[i]=(short)temp; } } }
// This version is used for floating-point DCT implementations. static void forward_DCT_float(jpeg_compress cinfo, jpeg_component_info compptr, byte[][] sample_data, short[][] coef_blocks, int coef_offset, uint start_row, uint start_col, uint num_blocks) { // This routine is heavily used, so it's worth coding it tightly jpeg_lossy_c_codec lossyc=(jpeg_lossy_c_codec)cinfo.coef; fdct_controller fdct=(fdct_controller)lossyc.fdct_private; float_DCT_method_ptr do_dct=fdct.do_float_dct; double[] divisors=fdct.float_divisors[compptr.quant_tbl_no]; double[] workspace=new double[DCTSIZE2]; // work area for FDCT subroutine for(int bi=0; bi<num_blocks; bi++, start_col+=DCTSIZE) { // Load data into workspace, applying unsigned->signed conversion int wsptr=0; for(int elemr=0; elemr<DCTSIZE; elemr++) { byte[] elem=sample_data[start_row+elemr]; uint eptr=start_col; // unroll the inner loop workspace[wsptr++]=elem[eptr++]-CENTERJSAMPLE; workspace[wsptr++]=elem[eptr++]-CENTERJSAMPLE; workspace[wsptr++]=elem[eptr++]-CENTERJSAMPLE; workspace[wsptr++]=elem[eptr++]-CENTERJSAMPLE; workspace[wsptr++]=elem[eptr++]-CENTERJSAMPLE; workspace[wsptr++]=elem[eptr++]-CENTERJSAMPLE; workspace[wsptr++]=elem[eptr++]-CENTERJSAMPLE; workspace[wsptr++]=elem[eptr++]-CENTERJSAMPLE; } // Perform the DCT do_dct(workspace); // Quantize/descale the coefficients, and store into coef_blocks[] //old short[] output_ptr=coef_blocks[coef_offset][bi]; short[] output_ptr=coef_blocks[coef_offset+bi]; for(int i=0; i<DCTSIZE2; i++) { // Apply the quantization and scaling factor double temp=workspace[i]*divisors[i]; // Round to nearest integer. // Since C does not specify the direction of rounding for negative // quotients, we have to force the dividend positive for portability. // The maximum coefficient size is +-16K (for 12-bit data), so this // code should work for either 16-bit or 32-bit ints. output_ptr[i]=(short)((int)(temp+16384.5)-16384); } } }
// This version is used for floating-point DCT implementations. private void forwardDCTFloatImpl(jpeg_component_info compptr, byte[][] sample_data, JBLOCK[] coef_blocks, int start_row, int start_col, int num_blocks) { /* This routine is heavily used, so it's worth coding it tightly. */ float_DCT_method_ptr do_dct = do_float_dct[compptr.Component_index]; float[] divisors = m_dctTables[compptr.Component_index].float_array; float[] workspace = new float[JpegConstants.DCTSIZE2]; /* work area for FDCT subroutine */ for (int bi = 0; bi < num_blocks; bi++, start_col += compptr.DCT_h_scaled_size) { /* Perform the DCT */ do_dct(workspace, sample_data, start_row, start_col); /* Quantize/descale the coefficients, and store into coef_blocks[] */ for (int i = 0; i < JpegConstants.DCTSIZE2; i++) { /* Apply the quantization and scaling factor */ float temp = workspace[i] * divisors[i]; /* Round to nearest integer. * Since C does not specify the direction of rounding for negative * quotients, we have to force the dividend positive for portability. * The maximum coefficient size is +-16K (for 12-bit data), so this * code should work for either 16-bit or 32-bit ints. */ coef_blocks[bi][i] = (short)((int)(temp + (float)16384.5) - 16384); } } }
// This version is used for integer DCT implementations. private void forwardDCTImpl(jpeg_component_info compptr, byte[][] sample_data, JBLOCK[] coef_blocks, int start_row, int start_col, int num_blocks) { /* This routine is heavily used, so it's worth coding it tightly. */ forward_DCT_method_ptr do_dct = this.do_dct[compptr.Component_index]; int[] divisors = m_dctTables[compptr.Component_index].int_array; int[] workspace = new int[JpegConstants.DCTSIZE2]; /* work area for FDCT subroutine */ for (int bi = 0; bi < num_blocks; bi++, start_col += compptr.DCT_h_scaled_size) { /* Perform the DCT */ do_dct(workspace, sample_data, start_row, start_col); /* Quantize/descale the coefficients, and store into coef_blocks[] */ for (int i = 0; i < JpegConstants.DCTSIZE2; i++) { int qval = divisors[i]; int temp = workspace[i]; if (temp < 0) { temp = -temp; temp += qval >> 1; /* for rounding */ if (temp >= qval) temp /= qval; else temp = 0; temp = -temp; } else { temp += qval >> 1; /* for rounding */ if (temp >= qval) temp /= qval; else temp = 0; } coef_blocks[bi][i] = (short)temp; } } }
// Perform dequantization and inverse DCT on one block of coefficients. #if! USE_UNSAFE_STUFF static void jpeg_idct_ifast(jpeg_decompress cinfo, jpeg_component_info compptr, short[] coef_block, byte[][] output_buf, uint output_row, uint output_col) { int[] workspace=new int[DCTSIZE2]; // buffers data between passes // Pass 1: process columns from input, store into work array. short[] inptr=coef_block; int[] quantptr=compptr.dct_table; int[] wsptr=workspace; int ptr=0; for(int ctr=DCTSIZE; ctr>0; ctr--, ptr++) // ptr++: advance pointers to next column { // Due to quantization, we will usually find that many of the input // coefficients are zero, especially the AC terms. We can exploit this // by short-circuiting the IDCT calculation for any column in which all // the AC terms are zero. In that case each output is equal to the // DC coefficient (with scale factor as needed). // With typical images and quantization tables, half or more of the // column DCT calculations can be simplified this way. if(inptr[ptr+DCTSIZE*1]==0&&inptr[ptr+DCTSIZE*2]==0&&inptr[ptr+DCTSIZE*3]==0&&inptr[ptr+DCTSIZE*4]==0&& inptr[ptr+DCTSIZE*5]==0&&inptr[ptr+DCTSIZE*6]==0&&inptr[ptr+DCTSIZE*7]==0) { // AC terms all zero int dcval=inptr[ptr]*quantptr[ptr]; wsptr[ptr]=dcval; wsptr[ptr+DCTSIZE*1]=dcval; wsptr[ptr+DCTSIZE*2]=dcval; wsptr[ptr+DCTSIZE*3]=dcval; wsptr[ptr+DCTSIZE*4]=dcval; wsptr[ptr+DCTSIZE*5]=dcval; wsptr[ptr+DCTSIZE*6]=dcval; wsptr[ptr+DCTSIZE*7]=dcval; continue; } // Even part int tmp0=inptr[ptr]*quantptr[ptr]; int tmp1=inptr[ptr+DCTSIZE*2]*quantptr[ptr+DCTSIZE*2]; int tmp2=inptr[ptr+DCTSIZE*4]*quantptr[ptr+DCTSIZE*4]; int tmp3=inptr[ptr+DCTSIZE*6]*quantptr[ptr+DCTSIZE*6]; int tmp10=tmp0+tmp2; // phase 3 int tmp11=tmp0-tmp2; int tmp13=tmp1+tmp3; // phases 5-3 int tmp12=(((tmp1-tmp3)*FIX_1_414213562)>>8)-tmp13; // 2*c4 tmp0=tmp10+tmp13; // phase 2 tmp3=tmp10-tmp13; tmp1=tmp11+tmp12; tmp2=tmp11-tmp12; // Odd part int tmp4=inptr[ptr+DCTSIZE*1]*quantptr[ptr+DCTSIZE*1]; int tmp5=inptr[ptr+DCTSIZE*3]*quantptr[ptr+DCTSIZE*3]; int tmp6=inptr[ptr+DCTSIZE*5]*quantptr[ptr+DCTSIZE*5]; int tmp7=inptr[ptr+DCTSIZE*7]*quantptr[ptr+DCTSIZE*7]; int z13=tmp6+tmp5; // phase 6 int z10=tmp6-tmp5; int z11=tmp4+tmp7; int z12=tmp4-tmp7; tmp7=z11+z13; // phase 5 tmp11=((z11-z13)*FIX_1_414213562)>>8; // 2*c4 int z5=((z10+z12)*FIX_1_847759065)>>8; // 2*c2 tmp10=((z12*FIX_1_082392200)>>8)-z5; // 2*(c2-c6) tmp12=((z10*-FIX_2_613125930)>>8)+z5; // -2*(c2+c6) tmp6=tmp12-tmp7; // phase 2 tmp5=tmp11-tmp6; tmp4=tmp10+tmp5; wsptr[ptr]=tmp0+tmp7; wsptr[ptr+DCTSIZE*7]=tmp0-tmp7; wsptr[ptr+DCTSIZE*1]=tmp1+tmp6; wsptr[ptr+DCTSIZE*6]=tmp1-tmp6; wsptr[ptr+DCTSIZE*2]=tmp2+tmp5; wsptr[ptr+DCTSIZE*5]=tmp2-tmp5; wsptr[ptr+DCTSIZE*4]=tmp3+tmp4; wsptr[ptr+DCTSIZE*3]=tmp3-tmp4; } // Pass 2: process rows from work array, store into output array. ptr=0; for(int ctr=0; ctr<DCTSIZE; ctr++) { byte[] outptr=output_buf[output_row+ctr]; // Rows of zeroes can be exploited in the same way as we did with columns. // However, the column calculation has created many nonzero AC terms, so // the simplification applies less often (typically 5% to 10% of the time). // On machines with very fast multiplication, it's possible that the // test takes more time than it's worth. In that case this section // may be commented out. #if !NO_ZERO_ROW_TEST if(wsptr[ptr+1]==0&&wsptr[ptr+2]==0&&wsptr[ptr+3]==0&&wsptr[ptr+4]==0&& wsptr[ptr+5]==0&&wsptr[ptr+6]==0&&wsptr[ptr+7]==0) { // AC terms all zero int dc=CENTERJSAMPLE+(wsptr[ptr]>>5); byte dcval=(byte)((dc>=MAXJSAMPLE)?MAXJSAMPLE:((dc<0)?0:dc)); outptr[output_col]=dcval; outptr[output_col+1]=dcval; outptr[output_col+2]=dcval; outptr[output_col+3]=dcval; outptr[output_col+4]=dcval; outptr[output_col+5]=dcval; outptr[output_col+6]=dcval; outptr[output_col+7]=dcval; ptr+=DCTSIZE; // advance pointer to next row continue; } #endif // Even part int tmp10=wsptr[ptr]+wsptr[ptr+4]; int tmp11=wsptr[ptr]-wsptr[ptr+4]; int tmp13=wsptr[ptr+2]+wsptr[ptr+6]; int tmp12=(((wsptr[ptr+2]-wsptr[ptr+6])*FIX_1_414213562)>>8)-tmp13; int tmp0=tmp10+tmp13; int tmp3=tmp10-tmp13; int tmp1=tmp11+tmp12; int tmp2=tmp11-tmp12; // Odd part int z13=wsptr[ptr+5]+wsptr[ptr+3]; int z10=wsptr[ptr+5]-wsptr[ptr+3]; int z11=wsptr[ptr+1]+wsptr[ptr+7]; int z12=wsptr[ptr+1]-wsptr[ptr+7]; int tmp7=z11+z13; // phase 5 tmp11=((z11-z13)*FIX_1_414213562)>>8; // 2*c4 int z5=((z10+z12)*FIX_1_847759065)>>8; // 2*c2 tmp10=((z12*FIX_1_082392200)>>8)-z5; // 2*(c2-c6) tmp12=((z10*-FIX_2_613125930)>>8)+z5; // -2*(c2+c6) int tmp6=tmp12-tmp7; // phase 2 int tmp5=tmp11-tmp6; int tmp4=tmp10+tmp5; // Final output stage: scale down by a factor of 8 and range-limit int x; x=CENTERJSAMPLE+((tmp0+tmp7)>>5); outptr[output_col+0]=(byte)((x>=MAXJSAMPLE)?MAXJSAMPLE:((x<0)?0:x)); x=CENTERJSAMPLE+((tmp0-tmp7)>>5); outptr[output_col+7]=(byte)((x>=MAXJSAMPLE)?MAXJSAMPLE:((x<0)?0:x)); x=CENTERJSAMPLE+((tmp1+tmp6)>>5); outptr[output_col+1]=(byte)((x>=MAXJSAMPLE)?MAXJSAMPLE:((x<0)?0:x)); x=CENTERJSAMPLE+((tmp1-tmp6)>>5); outptr[output_col+6]=(byte)((x>=MAXJSAMPLE)?MAXJSAMPLE:((x<0)?0:x)); x=CENTERJSAMPLE+((tmp2+tmp5)>>5); outptr[output_col+2]=(byte)((x>=MAXJSAMPLE)?MAXJSAMPLE:((x<0)?0:x)); x=CENTERJSAMPLE+((tmp2-tmp5)>>5); outptr[output_col+5]=(byte)((x>=MAXJSAMPLE)?MAXJSAMPLE:((x<0)?0:x)); x=CENTERJSAMPLE+((tmp3+tmp4)>>5); outptr[output_col+4]=(byte)((x>=MAXJSAMPLE)?MAXJSAMPLE:((x<0)?0:x)); x=CENTERJSAMPLE+((tmp3-tmp4)>>5); outptr[output_col+3]=(byte)((x>=MAXJSAMPLE)?MAXJSAMPLE:((x<0)?0:x)); ptr+=DCTSIZE; // advance pointer to next row } }