/// <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; } }
// 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; } }
// Routines to write specific marker types. // Emit a DQT marker // Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking static int emit_dqt(jpeg_compress cinfo, int index) { JQUANT_TBL qtbl=cinfo.quant_tbl_ptrs[index]; if(qtbl==null) ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_NO_QUANT_TABLE, index); int prec=0; for(int i=0; i<DCTSIZE2; i++) { if(qtbl.quantval[i]>255) prec=1; } if(!qtbl.sent_table) { emit_marker(cinfo, JPEG_MARKER.M_DQT); emit_2bytes(cinfo, prec!=0?DCTSIZE2*2+1+2:DCTSIZE2+1+2); emit_byte(cinfo, index+(prec<<4)); for(int i=0; i<DCTSIZE2; i++) { // The table entries must be emitted in zigzag order. uint qval=qtbl.quantval[jpeg_natural_order[i]]; if(prec!=0) emit_byte(cinfo, (int)(qval>>8)); emit_byte(cinfo, (int)(qval&0xFF)); } qtbl.sent_table=true; } return prec; }
/// <summary> /// Determine whether block smoothing is applicable and safe. /// We also latch the current states of the coef_bits[] entries for the /// AC coefficients; otherwise, if the input side of the decompressor /// advances into a new scan, we might think the coefficients are known /// more accurately than they really are. /// </summary> private bool smoothing_ok() { if (!m_cinfo.m_progressive_mode || m_cinfo.m_coef_bits == null) { return(false); } /* Allocate latch area if not already done */ if (m_coef_bits_latch == null) { m_coef_bits_latch = new int[m_cinfo.m_num_components * SAVED_COEFS]; m_coef_bits_savedOffset = 0; } bool smoothing_useful = false; for (int ci = 0; ci < m_cinfo.m_num_components; ci++) { /* All components' quantization values must already be latched. */ JQUANT_TBL qtable = m_cinfo.Comp_info[ci].quant_table; if (qtable == null) { return(false); } /* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */ if (qtable.quantval[0] == 0 || qtable.quantval[Q01_POS] == 0 || qtable.quantval[Q10_POS] == 0 || qtable.quantval[Q20_POS] == 0 || qtable.quantval[Q11_POS] == 0 || qtable.quantval[Q02_POS] == 0) { return(false); } /* DC values must be at least partly known for all components. */ if (m_cinfo.m_coef_bits[ci][0] < 0) { return(false); } /* Block smoothing is helpful if some AC coefficients remain inaccurate. */ for (int coefi = 1; coefi <= 5; coefi++) { m_coef_bits_latch[m_coef_bits_savedOffset + coefi] = m_cinfo.m_coef_bits[ci][coefi]; if (m_cinfo.m_coef_bits[ci][coefi] != 0) { smoothing_useful = true; } } m_coef_bits_savedOffset += SAVED_COEFS; } return(smoothing_useful); }
// Convenience routines for allocating quantization and Huffman tables. // (Would jutils.cs be a more reasonable place to put these?) public static JQUANT_TBL jpeg_alloc_quant_table(jpeg_common cinfo) { JQUANT_TBL tbl = null; try { tbl = new JQUANT_TBL(); tbl.sent_table = false; // make sure this is false in any new table } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } return(tbl); }
/// <summary> /// Emit a DQT marker /// </summary> /// <param name="index">The index.</param> /// <returns>the precision used (0 = 8bits, 1 = 16bits) for baseline checking</returns> private int emit_dqt(int index) { JQUANT_TBL qtbl = m_cinfo.m_quant_tbl_ptrs[index]; if (qtbl == null) { m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_NO_QUANT_TABLE, index); } int prec = 0; for (int i = 0; i <= m_cinfo.lim_Se; i++) { if (qtbl.quantval[m_cinfo.natural_order[i]] > 255) { prec = 1; } } if (!qtbl.Sent_table) { emit_marker(JPEG_MARKER.DQT); emit_2bytes(prec != 0 ? m_cinfo.lim_Se * 2 + 2 + 1 + 2 : m_cinfo.lim_Se + 1 + 1 + 2); emit_byte(index + (prec << 4)); for (int i = 0; i <= m_cinfo.lim_Se; i++) { /* The table entries must be emitted in zigzag order. */ int qval = qtbl.quantval[m_cinfo.natural_order[i]]; if (prec != 0) { emit_byte(qval >> 8); } emit_byte(qval & 0xFF); } qtbl.Sent_table = true; } return(prec); }
// 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; } } }
// 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> /// 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; } }
/// <summary> /// Process a DQT marker /// </summary> private bool get_dqt() { int length; if (!m_cinfo.m_src.GetTwoBytes(out length)) { return(false); } length -= 2; while (length > 0) { int n; if (!m_cinfo.m_src.GetByte(out n)) { return(false); } int prec = n >> 4; n &= 0x0F; m_cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_DQT, n, prec); if (n >= JpegConstants.NUM_QUANT_TBLS) { m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_DQT_INDEX, n); } if (m_cinfo.m_quant_tbl_ptrs[n] == null) { m_cinfo.m_quant_tbl_ptrs[n] = new JQUANT_TBL(); } JQUANT_TBL quant_ptr = m_cinfo.m_quant_tbl_ptrs[n]; for (int i = 0; i < JpegConstants.DCTSIZE2; i++) { int tmp; if (prec != 0) { int temp = 0; if (!m_cinfo.m_src.GetTwoBytes(out temp)) { return(false); } tmp = temp; } else { int temp = 0; if (!m_cinfo.m_src.GetByte(out temp)) { return(false); } tmp = temp; } /* We convert the zigzag-order table to natural array order. */ quant_ptr.quantval[JpegUtils.jpeg_natural_order[i]] = (short)tmp; } if (m_cinfo.m_err.m_trace_level >= 2) { for (int i = 0; i < JpegConstants.DCTSIZE2; i += 8) { m_cinfo.TRACEMS(2, J_MESSAGE_CODE.JTRC_QUANTVALS, quant_ptr.quantval[i], quant_ptr.quantval[i + 1], quant_ptr.quantval[i + 2], quant_ptr.quantval[i + 3], quant_ptr.quantval[i + 4], quant_ptr.quantval[i + 5], quant_ptr.quantval[i + 6], quant_ptr.quantval[i + 7]); } } length -= JpegConstants.DCTSIZE2 + 1; if (prec != 0) { length -= JpegConstants.DCTSIZE2; } } if (length != 0) { m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_BAD_LENGTH); } return(true); }
/// <summary> /// Initialize for a processing pass. /// Verify that all referenced Q-tables are present, and set up /// the divisor table for each one. /// In the current implementation, DCT of all components is done during /// the first pass, even if only some components will be output in the /// first scan. Hence all components should be examined here. /// </summary> public virtual void start_pass() { for (int ci = 0; ci < m_cinfo.m_num_components; ci++) { int qtblno = m_cinfo.Component_info[ci].Quant_tbl_no; /* Make sure specified quantization table is present */ 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); } JQUANT_TBL qtbl = m_cinfo.m_quant_tbl_ptrs[qtblno]; /* Compute divisors for this quant table */ /* We may do this more than once for same table, but it's not a big deal */ int i = 0; switch (m_cinfo.m_dct_method) { case J_DCT_METHOD.JDCT_ISLOW: /* For LL&M IDCT method, divisors are equal to raw quantization * coefficients multiplied by 8 (to counteract scaling). */ if (m_divisors[qtblno] == null) { m_divisors[qtblno] = new int [JpegConstants.DCTSIZE2]; } for (i = 0; i < JpegConstants.DCTSIZE2; i++) { m_divisors[qtblno][i] = ((int)qtbl.quantval[i]) << 3; } break; case J_DCT_METHOD.JDCT_IFAST: if (m_divisors[qtblno] == null) { m_divisors[qtblno] = new int [JpegConstants.DCTSIZE2]; } for (i = 0; i < JpegConstants.DCTSIZE2; i++) { m_divisors[qtblno][i] = JpegUtils.DESCALE((int)qtbl.quantval[i] * (int)aanscales[i], CONST_BITS - 3); } break; case J_DCT_METHOD.JDCT_FLOAT: if (m_float_divisors[qtblno] == null) { m_float_divisors[qtblno] = new float [JpegConstants.DCTSIZE2]; } float[] fdtbl = m_float_divisors[qtblno]; i = 0; for (int row = 0; row < JpegConstants.DCTSIZE; row++) { for (int col = 0; col < JpegConstants.DCTSIZE; col++) { fdtbl[i] = (float)(1.0 / (((double)qtbl.quantval[i] * aanscalefactor[row] * aanscalefactor[col] * 8.0))); i++; } } break; default: m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_NOT_COMPILED); break; } } }
// Variant of decompress_data for use when doing block smoothing. static CONSUME_INPUT decompress_smooth_data(jpeg_decompress cinfo, byte[][][] output_buf) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; d_coef_controller coef = (d_coef_controller)lossyd.coef_private; // Force some input to be done if we are getting ahead of the input. while (cinfo.input_scan_number <= cinfo.output_scan_number && !cinfo.inputctl.eoi_reached) { if (cinfo.input_scan_number == cinfo.output_scan_number) { // If input is working on current scan, we ordinarily want it to // have completed the current row. But if input scan is DC, // we want it to keep one row ahead so that next block row's DC // values are up to date. uint delta = (cinfo.Ss == 0)?1u:0u; if (cinfo.input_iMCU_row > cinfo.output_iMCU_row + delta) { break; } } if (cinfo.inputctl.consume_input(cinfo) == CONSUME_INPUT.JPEG_SUSPENDED) { return(CONSUME_INPUT.JPEG_SUSPENDED); } } uint last_iMCU_row = cinfo.total_iMCU_rows - 1; short[] workspace = new short[DCTSIZE2]; // OK, output from the arrays. for (int ci = 0; ci < cinfo.num_components; ci++) { jpeg_component_info compptr = cinfo.comp_info[ci]; // Don't bother to IDCT an uninteresting component. if (!compptr.component_needed) { continue; } // Count non-dummy DCT block rows in this iMCU row. int block_rows, access_rows; bool last_row; if (cinfo.output_iMCU_row < last_iMCU_row) { block_rows = compptr.v_samp_factor; access_rows = block_rows * 2; // this and next iMCU row last_row = false; } else { // NB: can't use last_row_height here; it is input-side-dependent! block_rows = (int)(compptr.height_in_blocks % compptr.v_samp_factor); if (block_rows == 0) { block_rows = compptr.v_samp_factor; } access_rows = block_rows; // this iMCU row only last_row = true; } // Align the buffer for this component. bool first_row; short[][][] buffer; int buffer_ind; if (cinfo.output_iMCU_row > 0) { access_rows += compptr.v_samp_factor; // prior iMCU row too buffer = coef.whole_image[ci]; buffer_ind = (int)cinfo.output_iMCU_row * compptr.v_samp_factor; // point to current iMCU row first_row = false; } else { buffer = coef.whole_image[ci]; buffer_ind = 0; first_row = true; } // Fetch component-dependent info int[] coef_bits = coef.coef_bits_latch[ci]; JQUANT_TBL quanttbl = compptr.quant_table; int Q00 = quanttbl.quantval[0]; int Q01 = quanttbl.quantval[Q01_POS]; int Q10 = quanttbl.quantval[Q10_POS]; int Q20 = quanttbl.quantval[Q20_POS]; int Q11 = quanttbl.quantval[Q11_POS]; int Q02 = quanttbl.quantval[Q02_POS]; inverse_DCT_method_ptr inverse_DCT = lossyd.inverse_DCT[ci]; uint output_buf_ind = 0; // Loop over all DCT blocks to be processed. for (int block_row = 0; block_row < block_rows; block_row++) { short[][] buffer_ptr = buffer[buffer_ind + block_row]; short[][] prev_block_row; short[][] next_block_row; if (first_row && block_row == 0) { prev_block_row = buffer_ptr; } else { prev_block_row = buffer[buffer_ind + block_row - 1]; } if (last_row && block_row == block_rows - 1) { next_block_row = buffer_ptr; } else { next_block_row = buffer[buffer_ind + block_row + 1]; } // We fetch the surrounding DC values using a sliding-register approach. // Initialize all nine here so as to do the right thing on narrow pics. int DC1, DC2, DC3, DC4, DC5, DC6, DC7, DC8, DC9; DC1 = DC2 = DC3 = (int)prev_block_row[0][0]; DC4 = DC5 = DC6 = (int)buffer_ptr[0][0]; DC7 = DC8 = DC9 = (int)next_block_row[0][0]; int ind = 1; uint output_col = 0; uint last_block_column = compptr.width_in_blocks - 1; for (uint block_num = 0; block_num <= last_block_column; block_num++) { // Fetch current DCT block into workspace so we can modify it. buffer_ptr.CopyTo(workspace, 0); // Update DC values if (block_num < last_block_column) { DC3 = (int)prev_block_row[ind][0]; DC6 = (int)buffer_ptr[ind][0]; DC9 = (int)next_block_row[ind][0]; } // Compute coefficient estimates per K.8. // An estimate is applied only if coefficient is still zero, // and is not known to be fully accurate. // AC01 int Al = coef_bits[1]; if (Al != 0 && workspace[1] == 0) { int num = 36 * Q00 * (DC4 - DC6); int pred; if (num >= 0) { pred = (int)(((Q01 << 7) + num) / (Q01 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } } else { pred = (int)(((Q01 << 7) - num) / (Q01 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } pred = -pred; } workspace[1] = (short)pred; } // AC10 Al = coef_bits[2]; if (Al != 0 && workspace[8] == 0) { int num = 36 * Q00 * (DC2 - DC8); int pred; if (num >= 0) { pred = (int)(((Q10 << 7) + num) / (Q10 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } } else { pred = (int)(((Q10 << 7) - num) / (Q10 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } pred = -pred; } workspace[8] = (short)pred; } // AC20 Al = coef_bits[3]; if (Al != 0 && workspace[16] == 0) { int num = 9 * Q00 * (DC2 + DC8 - 2 * DC5); int pred; if (num >= 0) { pred = (int)(((Q20 << 7) + num) / (Q20 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } } else { pred = (int)(((Q20 << 7) - num) / (Q20 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } pred = -pred; } workspace[16] = (short)pred; } // AC11 Al = coef_bits[4]; if (Al != 0 && workspace[9] == 0) { int num = 5 * Q00 * (DC1 - DC3 - DC7 + DC9); int pred; if (num >= 0) { pred = (int)(((Q11 << 7) + num) / (Q11 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } } else { pred = (int)(((Q11 << 7) - num) / (Q11 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } pred = -pred; } workspace[9] = (short)pred; } // AC02 Al = coef_bits[5]; if (Al != 0 && workspace[2] == 0) { int num = 9 * Q00 * (DC4 + DC6 - 2 * DC5); int pred; if (num >= 0) { pred = (int)(((Q02 << 7) + num) / (Q02 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } } else { pred = (int)(((Q02 << 7) - num) / (Q02 << 8)); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } pred = -pred; } workspace[2] = (short)pred; } // OK, do the IDCT inverse_DCT(cinfo, compptr, workspace, output_buf[ci], output_buf_ind, output_col); // Advance for next column DC1 = DC2; DC2 = DC3; DC4 = DC5; DC5 = DC6; DC7 = DC8; DC8 = DC9; ind++; output_col += compptr.DCT_scaled_size; } output_buf_ind += compptr.DCT_scaled_size; } } if (++(cinfo.output_iMCU_row) < cinfo.total_iMCU_rows) { return(CONSUME_INPUT.JPEG_ROW_COMPLETED); } return(CONSUME_INPUT.JPEG_SCAN_COMPLETED); }
// Determine whether block smoothing is applicable and safe. // We also latch the current states of the coef_bits[] entries for the // AC coefficients; otherwise, if the input side of the decompressor // advances into a new scan, we might think the coefficients are known // more accurately than they really are. static bool smoothing_ok(jpeg_decompress cinfo) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; d_coef_controller coef = (d_coef_controller)lossyd.coef_private; if (cinfo.process != J_CODEC_PROCESS.JPROC_PROGRESSIVE || cinfo.coef_bits == null) { return(false); } // Allocate latch area if not already done if (coef.coef_bits_latch == null) { try { coef.coef_bits_latch = new int[cinfo.num_components][]; for (int i = 0; i < cinfo.num_components; i++) { coef.coef_bits_latch[i] = new int[SAVED_COEFS]; } } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } } bool smoothing_useful = false; for (int ci = 0; ci < cinfo.num_components; ci++) { jpeg_component_info compptr = cinfo.comp_info[ci]; // All components' quantization values must already be latched. JQUANT_TBL qtable = compptr.quant_table; if (qtable == null) { return(false); } // Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. if (qtable.quantval[0] == 0 || qtable.quantval[Q01_POS] == 0 || qtable.quantval[Q10_POS] == 0 || qtable.quantval[Q20_POS] == 0 || qtable.quantval[Q11_POS] == 0 || qtable.quantval[Q02_POS] == 0) { return(false); } // DC values must be at least partly known for all components. int[] coef_bits = cinfo.coef_bits[ci]; if (coef_bits[0] < 0) { return(false); } // Block smoothing is helpful if some AC coefficients remain inaccurate. for (int coefi = 1; coefi <= 5; coefi++) { coef.coef_bits_latch[ci][coefi] = coef_bits[coefi]; if (coef_bits[coefi] != 0) { smoothing_useful = true; } } } return(smoothing_useful); }
// Initialize for a processing pass. // Verify that all referenced Q-tables are present, and set up // the divisor table for each one. // In the current implementation, DCT of all components is done during // the first pass, even if only some components will be output in the // first scan. Hence all components should be examined here. static void start_pass_fdctmgr(jpeg_compress cinfo) { jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef; fdct_controller fdct = (fdct_controller)lossyc.fdct_private; for (int ci = 0; ci < cinfo.num_components; ci++) { jpeg_component_info compptr = cinfo.comp_info[ci]; int qtblno = compptr.quant_tbl_no; // Make sure specified quantization table is present if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || cinfo.quant_tbl_ptrs[qtblno] == null) { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_NO_QUANT_TABLE, qtblno); } JQUANT_TBL qtbl = cinfo.quant_tbl_ptrs[qtblno]; // Compute divisors for this quant table // We may do this more than once for same table, but it's not a big deal if (fdct.divisors[qtblno] == null) { try { fdct.divisors[qtblno] = new int[DCTSIZE2]; } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } } int[] dtbl = fdct.divisors[qtblno]; for (int i = 0; i < DCTSIZE2; i++) { dtbl[i] = ((int)qtbl.quantval[i] * aanscales[i] + 1024) >> 11; } #if DCT_FLOAT_SUPPORTED if (fdct.float_divisors[qtblno] == null) { try { fdct.float_divisors[qtblno] = new double[DCTSIZE2]; } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } } double[] fdtbl = fdct.float_divisors[qtblno]; int di = 0; for (int row = 0; row < DCTSIZE; row++) { for (int col = 0; col < DCTSIZE; col++) { fdtbl[di] = 1.0 / (qtbl.quantval[di] * aanscalefactor[row] * aanscalefactor[col] * 8.0); di++; } } #endif } }