public override bool encode_mcu(JBLOCK[][] MCU_data) { if (m_gather_statistics) return encode_mcu_gather(MCU_data); return encode_mcu_huff(MCU_data); }
public jpeg_d_coef_controller(jpeg_decompress_struct cinfo, bool need_full_buffer) { m_cinfo = cinfo; /* Create the coefficient buffer. */ if (need_full_buffer) { /* Allocate a full-image virtual 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.m_num_components; ci++) { m_whole_image[ci] = jpeg_common_struct.CreateBlocksArray( JpegUtils.jround_up(cinfo.Comp_info[ci].Width_in_blocks, cinfo.Comp_info[ci].H_samp_factor), JpegUtils.jround_up(cinfo.Comp_info[ci].height_in_blocks, cinfo.Comp_info[ci].V_samp_factor)); m_whole_image[ci].ErrorProcessor = cinfo; } m_useDummyConsumeData = false; m_decompressor = DecompressorType.Ordinary; m_coef_arrays = m_whole_image; /* link to virtual arrays */ } else { /* We only need a single-MCU buffer. */ for (int i = 0; i < JpegConstants.D_MAX_BLOCKS_IN_MCU; i++) { m_MCU_buffer[i] = new JBLOCK(); } m_useDummyConsumeData = true; m_decompressor = DecompressorType.OnePass; m_coef_arrays = null; /* flag for no virtual arrays */ } }
public my_c_coef_controller(jpeg_compress_struct cinfo, bool need_full_buffer) { m_cinfo = cinfo; /* Create the coefficient buffer. */ if (need_full_buffer) { /* Allocate a full-image virtual array for each component, */ /* padded to a multiple of samp_factor DCT blocks in each direction. */ for (int ci = 0; ci < cinfo.m_num_components; ci++) { m_whole_image[ci] = jpeg_common_struct.CreateBlocksArray( JpegUtils.jround_up(cinfo.Component_info[ci].Width_in_blocks, cinfo.Component_info[ci].H_samp_factor), JpegUtils.jround_up(cinfo.Component_info[ci].height_in_blocks, cinfo.Component_info[ci].V_samp_factor)); m_whole_image[ci].ErrorProcessor = cinfo; } } else { /* We only need a single-MCU buffer. */ JBLOCK[] buffer = new JBLOCK[JpegConstants.C_MAX_BLOCKS_IN_MCU]; for (int i = 0; i < JpegConstants.C_MAX_BLOCKS_IN_MCU; i++) buffer[i] = new JBLOCK(); for (int i = 0; i < JpegConstants.C_MAX_BLOCKS_IN_MCU; i++) { m_MCU_buffer[i] = new JBLOCK[JpegConstants.C_MAX_BLOCKS_IN_MCU - i]; for (int j = i; j < JpegConstants.C_MAX_BLOCKS_IN_MCU; j++) m_MCU_buffer[i][j - i] = buffer[j]; } /* flag for no virtual arrays */ m_whole_image[0] = null; } }
/// <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); }
private byte[] Hash(JBLOCK block, int[] group) { using (var ms = new MemoryStream()) using (var sw = new BinaryWriter(ms)) { group.Select(i => block[i]).ToList().ForEach(sw.Write); sw.Flush(); ms.Seek(0, SeekOrigin.Begin); return(_md5.ComputeHash(ms).Take(BytesPerGroup).ToArray()); } }
private void EncodeGroup(JBLOCK block, int[] @group, byte[] data) { var deviation = 1; while (!Go(block, @group, data, 0, deviation)) { deviation++; Console.Out.WriteLine("deviation = {0}", deviation); } Console.Out.WriteLine("block encrypted"); }
private byte[] DecodeBlock(JBLOCK block) { using (var ms = new MemoryStream()) { foreach (var @group in Groups) { var h = DecodeGroup(block, @group); ms.Write(h, 0, h.Length); } return(ms.GetBuffer().Take(BytesPerBlock).ToArray()); } }
private void EncodeBlock(JBLOCK block, byte[] data) { for (var i = 0; i < Groups.Length; i++) { var currentGroupData = data.Skip(i * BytesPerGroup).Take(BytesPerGroup).ToArray(); if (UseOldEncoder) { EncodeGroupOld(block, Groups[i], currentGroupData); } else { EncodeGroup(block, Groups[i], currentGroupData); } } }
private void EncodeGroupOld(JBLOCK block, int[] @group, byte[] data) { var tries = 0; while (!Hash(block, group).SequenceEqual(data)) { var index = @group[_random.Next(@group.Length)]; block[index] += _random.Next(2) == 0 ? (short)1 : (short)-1; if (tries++ > 10000000) { throw new Exception("Max tries reached"); } } Console.Out.WriteLine("block encrypted"); }
/// <summary> /// Initialize coefficient buffer controller. /// /// Each passed coefficient array must be the right size for that /// coefficient: width_in_blocks wide and height_in_blocks high, /// with unit height at least v_samp_factor. /// </summary> public my_trans_c_coef_controller(jpeg_compress_struct cinfo, jvirt_array<JBLOCK>[] coef_arrays) { m_cinfo = cinfo; /* Save pointer to virtual arrays */ m_whole_image = coef_arrays; /* Allocate and pre-zero space for dummy DCT blocks. */ JBLOCK[] buffer = new JBLOCK[JpegConstants.C_MAX_BLOCKS_IN_MCU]; for (int i = 0; i < JpegConstants.C_MAX_BLOCKS_IN_MCU; i++) buffer[i] = new JBLOCK(); for (int i = 0; i < JpegConstants.C_MAX_BLOCKS_IN_MCU; i++) { m_dummy_buffer[i] = new JBLOCK[JpegConstants.C_MAX_BLOCKS_IN_MCU - i]; for (int j = i; j < JpegConstants.C_MAX_BLOCKS_IN_MCU; j++) m_dummy_buffer[i][j - i] = buffer[j]; } }
private bool Go(JBLOCK block, int[] @group, byte[] target, int pos, int deviation) { if (pos == @group.Length) { return(Hash(block, @group).SequenceEqual(target)); } for (var i = -deviation; i <= deviation; i++) { block[@group[pos]] += (short)i; if (Go(block, @group, target, pos + 1, deviation - Math.Abs(i))) { return(true); } block[@group[pos]] -= (short)i; } return(false); }
public my_c_coef_controller(jpeg_compress_struct cinfo, bool need_full_buffer) { m_cinfo = cinfo; /* Create the coefficient buffer. */ if (need_full_buffer) { /* Allocate a full-image virtual array for each component, */ /* padded to a multiple of samp_factor DCT blocks in each direction. */ for (int ci = 0; ci < cinfo.m_num_components; ci++) { m_whole_image[ci] = jpeg_common_struct.CreateBlocksArray( JpegUtils.jround_up(cinfo.Component_info[ci].Width_in_blocks, cinfo.Component_info[ci].H_samp_factor), JpegUtils.jround_up(cinfo.Component_info[ci].height_in_blocks, cinfo.Component_info[ci].V_samp_factor)); m_whole_image[ci].ErrorProcessor = cinfo; } } else { /* We only need a single-MCU buffer. */ JBLOCK[] buffer = new JBLOCK[JpegConstants.C_MAX_BLOCKS_IN_MCU]; for (int i = 0; i < JpegConstants.C_MAX_BLOCKS_IN_MCU; i++) { buffer[i] = new JBLOCK(); } for (int i = 0; i < JpegConstants.C_MAX_BLOCKS_IN_MCU; i++) { m_MCU_buffer[i] = new JBLOCK[JpegConstants.C_MAX_BLOCKS_IN_MCU - i]; for (int j = i; j < JpegConstants.C_MAX_BLOCKS_IN_MCU; j++) { m_MCU_buffer[i][j - i] = buffer[j]; } } /* flag for no virtual arrays */ m_whole_image[0] = null; } }
/// <summary> /// Initialize coefficient buffer controller. /// /// Each passed coefficient array must be the right size for that /// coefficient: width_in_blocks wide and height_in_blocks high, /// with unit height at least v_samp_factor. /// </summary> public my_trans_c_coef_controller(jpeg_compress_struct cinfo, jvirt_array <JBLOCK>[] coef_arrays) { m_cinfo = cinfo; /* Save pointer to virtual arrays */ m_whole_image = coef_arrays; /* Allocate and pre-zero space for dummy DCT blocks. */ JBLOCK[] buffer = new JBLOCK[JpegConstants.C_MAX_BLOCKS_IN_MCU]; for (int i = 0; i < JpegConstants.C_MAX_BLOCKS_IN_MCU; i++) { buffer[i] = new JBLOCK(); } for (int i = 0; i < JpegConstants.C_MAX_BLOCKS_IN_MCU; i++) { m_dummy_buffer[i] = new JBLOCK[JpegConstants.C_MAX_BLOCKS_IN_MCU - i]; for (int j = i; j < JpegConstants.C_MAX_BLOCKS_IN_MCU; j++) { m_dummy_buffer[i][j - i] = buffer[j]; } } }
/// <summary> /// Decode and return one MCU's worth of Huffman-compressed coefficients. /// The coefficients are reordered from zigzag order into natural array order, /// but are not dequantized. /// /// The i'th block of the MCU is stored into the block pointed to by /// MCU_data[i]. WE ASSUME THIS AREA HAS BEEN ZEROED BY THE CALLER. /// (Wholesale zeroing is usually a little faster than retail...) /// /// Returns false if data source requested suspension. In that case no /// changes have been made to permanent state. (Exception: some output /// coefficients may already have been assigned. This is harmless for /// this module, since we'll just re-assign them on the next call.) /// </summary> public override bool decode_mcu(JBLOCK[] MCU_data) { /* Process restart marker if needed; may have to suspend */ if (m_cinfo.m_restart_interval != 0) { if (m_restarts_to_go == 0) { if (!process_restart()) return false; } } /* If we've run out of data, just leave the MCU set to zeroes. * This way, we return uniform gray for the remainder of the segment. */ if (!m_insufficient_data) { /* Load up working state */ int get_buffer; int bits_left; bitread_working_state br_state = new bitread_working_state(); BITREAD_LOAD_STATE(m_bitstate, out get_buffer, out bits_left, ref br_state); savable_state state = new savable_state(); state.Assign(m_saved); /* Outer loop handles each block in the MCU */ for (int blkn = 0; blkn < m_cinfo.m_blocks_in_MCU; blkn++) { /* Decode a single block's worth of coefficients */ /* Section F.2.2.1: decode the DC coefficient difference */ int s; if (!HUFF_DECODE(out s, ref br_state, m_dc_cur_tbls[blkn], ref get_buffer, ref bits_left)) return false; if (s != 0) { if (!CHECK_BIT_BUFFER(ref br_state, s, ref get_buffer, ref bits_left)) return false; int r = GET_BITS(s, get_buffer, ref bits_left); s = HUFF_EXTEND(r, s); } if (m_dc_needed[blkn]) { /* Convert DC difference to actual value, update last_dc_val */ int ci = m_cinfo.m_MCU_membership[blkn]; s += state.last_dc_val[ci]; state.last_dc_val[ci] = s; /* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */ MCU_data[blkn][0] = (short) s; } if (m_ac_needed[blkn]) { /* Section F.2.2.2: decode the AC coefficients */ /* Since zeroes are skipped, output area must be cleared beforehand */ for (int k = 1; k < JpegConstants.DCTSIZE2; k++) { if (!HUFF_DECODE(out s, ref br_state, m_ac_cur_tbls[blkn], ref get_buffer, ref bits_left)) return false; int r = s >> 4; s &= 15; if (s != 0) { k += r; if (!CHECK_BIT_BUFFER(ref br_state, s, ref get_buffer, ref bits_left)) return false; r = GET_BITS(s, get_buffer, ref bits_left); s = HUFF_EXTEND(r, s); /* Output coefficient in natural (dezigzagged) order. * Note: the extra entries in jpeg_natural_order[] will save us * if k >= DCTSIZE2, which could happen if the data is corrupted. */ MCU_data[blkn][JpegUtils.jpeg_natural_order[k]] = (short) s; } else { if (r != 15) break; k += 15; } } } else { /* Section F.2.2.2: decode the AC coefficients */ /* In this path we just discard the values */ for (int k = 1; k < JpegConstants.DCTSIZE2; k++) { if (!HUFF_DECODE(out s, ref br_state, m_ac_cur_tbls[blkn], ref get_buffer, ref bits_left)) return false; int r = s >> 4; s &= 15; if (s != 0) { k += r; if (!CHECK_BIT_BUFFER(ref br_state, s, ref get_buffer, ref bits_left)) return false; DROP_BITS(s, ref bits_left); } else { if (r != 15) break; k += 15; } } } } /* Completed MCU, so update state */ BITREAD_SAVE_STATE(ref m_bitstate, get_buffer, bits_left); m_saved.Assign(state); } /* Account for restart interval (no-op if not using restarts) */ m_restarts_to_go--; return true; }
/// <summary> /// Trial-encode one MCU's worth of Huffman-compressed coefficients. /// No data is actually output, so no suspension return is possible. /// </summary> private bool encode_mcu_gather(JBLOCK[][] MCU_data) { /* Take care of restart intervals if needed */ if (m_cinfo.m_restart_interval != 0) { if (m_restarts_to_go == 0) { /* Re-initialize DC predictions to 0 */ for (int ci = 0; ci < m_cinfo.m_comps_in_scan; ci++) m_saved.last_dc_val[ci] = 0; /* Update restart state */ m_restarts_to_go = m_cinfo.m_restart_interval; } m_restarts_to_go--; } for (int blkn = 0; blkn < m_cinfo.m_blocks_in_MCU; blkn++) { int ci = m_cinfo.m_MCU_membership[blkn]; htest_one_block(MCU_data[blkn][0].data, m_saved.last_dc_val[ci], m_dc_count_ptrs[m_cinfo.Component_info[m_cinfo.m_cur_comp_info[ci]].Dc_tbl_no], m_ac_count_ptrs[m_cinfo.Component_info[m_cinfo.m_cur_comp_info[ci]].Ac_tbl_no]); m_saved.last_dc_val[ci] = MCU_data[blkn][0][0]; } return true; }
/// <summary> /// MCU decoding for AC successive approximation refinement scan. /// </summary> private static void undo_decode_mcu_AC_refine(JBLOCK[] block, int[] newnz_pos, int num_newnz) { /* Re-zero any output coefficients that we made newly nonzero */ while (num_newnz > 0) block[0][newnz_pos[--num_newnz]] = 0; }
/// <summary> /// Variant of decompress_data for use when doing block smoothing. /// </summary> private ReadResult decompress_smooth_data(ComponentBuffer[] output_buf) { /* Force some input to be done if we are getting ahead of the input. */ while (m_cinfo.m_input_scan_number <= m_cinfo.m_output_scan_number && !m_cinfo.m_inputctl.EOIReached()) { if (m_cinfo.m_input_scan_number == m_cinfo.m_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. */ int delta = (m_cinfo.m_Ss == 0) ? 1 : 0; if (m_cinfo.m_input_iMCU_row > m_cinfo.m_output_iMCU_row + delta) break; } if (m_cinfo.m_inputctl.consume_input() == ReadResult.JPEG_SUSPENDED) return ReadResult.JPEG_SUSPENDED; } int last_iMCU_row = m_cinfo.m_total_iMCU_rows - 1; /* OK, output from the virtual arrays. */ for (int ci = 0; ci < m_cinfo.m_num_components; ci++) { jpeg_component_info componentInfo = m_cinfo.Comp_info[ci]; /* Don't bother to IDCT an uninteresting component. */ if (!componentInfo.component_needed) continue; int block_rows; int access_rows; bool last_row; /* Count non-dummy DCT block rows in this iMCU row. */ if (m_cinfo.m_output_iMCU_row < last_iMCU_row) { block_rows = componentInfo.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 = componentInfo.height_in_blocks % componentInfo.V_samp_factor; if (block_rows == 0) block_rows = componentInfo.V_samp_factor; access_rows = block_rows; /* this iMCU row only */ last_row = true; } /* Align the virtual buffer for this component. */ JBLOCK[][] buffer = null; bool first_row; int bufferRowOffset = 0; if (m_cinfo.m_output_iMCU_row > 0) { access_rows += componentInfo.V_samp_factor; /* prior iMCU row too */ buffer = m_whole_image[ci].Access((m_cinfo.m_output_iMCU_row - 1) * componentInfo.V_samp_factor, access_rows); bufferRowOffset = componentInfo.V_samp_factor; /* point to current iMCU row */ first_row = false; } else { buffer = m_whole_image[ci].Access(0, access_rows); first_row = true; } /* Fetch component-dependent info */ int coefBitsOffset = ci * SAVED_COEFS; int Q00 = componentInfo.quant_table.quantval[0]; int Q01 = componentInfo.quant_table.quantval[Q01_POS]; int Q10 = componentInfo.quant_table.quantval[Q10_POS]; int Q20 = componentInfo.quant_table.quantval[Q20_POS]; int Q11 = componentInfo.quant_table.quantval[Q11_POS]; int Q02 = componentInfo.quant_table.quantval[Q02_POS]; int outputIndex = ci; /* Loop over all DCT blocks to be processed. */ for (int block_row = 0; block_row < block_rows; block_row++) { int bufferIndex = bufferRowOffset + block_row; int prev_block_row = 0; if (first_row && block_row == 0) prev_block_row = bufferIndex; else prev_block_row = bufferIndex - 1; int next_block_row = 0; if (last_row && block_row == block_rows - 1) next_block_row = bufferIndex; else next_block_row = bufferIndex + 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 = buffer[prev_block_row][0][0]; int DC2 = DC1; int DC3 = DC1; int DC4 = buffer[bufferIndex][0][0]; int DC5 = DC4; int DC6 = DC4; int DC7 = buffer[next_block_row][0][0]; int DC8 = DC7; int DC9 = DC7; int output_col = 0; int last_block_column = componentInfo.Width_in_blocks - 1; for (int block_num = 0; block_num <= last_block_column; block_num++) { /* Fetch current DCT block into workspace so we can modify it. */ JBLOCK workspace = new JBLOCK(); Buffer.BlockCopy(buffer[bufferIndex][0].data, 0, workspace.data, 0, workspace.data.Length * sizeof(short)); /* Update DC values */ if (block_num < last_block_column) { DC3 = buffer[prev_block_row][1][0]; DC6 = buffer[bufferIndex][1][0]; DC9 = buffer[next_block_row][1][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 = m_coef_bits_latch[m_coef_bits_savedOffset + coefBitsOffset + 1]; if (Al != 0 && workspace[1] == 0) { int pred; int num = 36 * Q00 * (DC4 - DC6); if (num >= 0) { pred = ((Q01 << 7) + num) / (Q01 << 8); if (Al > 0 && pred >= (1 << Al)) pred = (1 << Al) - 1; } else { pred = ((Q01 << 7) - num) / (Q01 << 8); if (Al > 0 && pred >= (1 << Al)) pred = (1 << Al) - 1; pred = -pred; } workspace[1] = (short) pred; } /* AC10 */ Al = m_coef_bits_latch[m_coef_bits_savedOffset + coefBitsOffset + 2]; if (Al != 0 && workspace[8] == 0) { int pred; int num = 36 * Q00 * (DC2 - DC8); if (num >= 0) { pred = ((Q10 << 7) + num) / (Q10 << 8); if (Al > 0 && pred >= (1 << Al)) pred = (1 << Al) - 1; } else { pred = ((Q10 << 7) - num) / (Q10 << 8); if (Al > 0 && pred >= (1 << Al)) pred = (1 << Al) - 1; pred = -pred; } workspace[8] = (short) pred; } /* AC20 */ Al = m_coef_bits_latch[m_coef_bits_savedOffset + coefBitsOffset + 3]; if (Al != 0 && workspace[16] == 0) { int pred; int num = 9 * Q00 * (DC2 + DC8 - 2 * DC5); if (num >= 0) { pred = ((Q20 << 7) + num) / (Q20 << 8); if (Al > 0 && pred >= (1 << Al)) pred = (1 << Al) - 1; } else { pred = ((Q20 << 7) - num) / (Q20 << 8); if (Al > 0 && pred >= (1 << Al)) pred = (1 << Al) - 1; pred = -pred; } workspace[16] = (short) pred; } /* AC11 */ Al = m_coef_bits_latch[m_coef_bits_savedOffset + coefBitsOffset + 4]; if (Al != 0 && workspace[9] == 0) { int pred; int num = 5 * Q00 * (DC1 - DC3 - DC7 + DC9); if (num >= 0) { pred = ((Q11 << 7) + num) / (Q11 << 8); if (Al > 0 && pred >= (1 << Al)) pred = (1 << Al) - 1; } else { pred = ((Q11 << 7) - num) / (Q11 << 8); if (Al > 0 && pred >= (1 << Al)) pred = (1 << Al) - 1; pred = -pred; } workspace[9] = (short) pred; } /* AC02 */ Al = m_coef_bits_latch[m_coef_bits_savedOffset + coefBitsOffset + 5]; if (Al != 0 && workspace[2] == 0) { int pred; int num = 9 * Q00 * (DC4 + DC6 - 2 * DC5); if (num >= 0) { pred = ((Q02 << 7) + num) / (Q02 << 8); if (Al > 0 && pred >= (1 << Al)) pred = (1 << Al) - 1; } else { pred = ((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 */ m_cinfo.m_idct.inverse(componentInfo.Component_index, workspace.data, output_buf[outputIndex], 0, output_col); /* Advance for next column */ DC1 = DC2; DC2 = DC3; DC4 = DC5; DC5 = DC6; DC7 = DC8; DC8 = DC9; bufferIndex++; prev_block_row++; next_block_row++; output_col += componentInfo.DCT_scaled_size; } outputIndex += componentInfo.DCT_scaled_size; } } m_cinfo.m_output_iMCU_row++; if (m_cinfo.m_output_iMCU_row < m_cinfo.m_total_iMCU_rows) return ReadResult.JPEG_ROW_COMPLETED; return ReadResult.JPEG_SCAN_COMPLETED; }
// This version is used for integer DCT implementations. private void forwardDCTImpl(int quant_tbl_no, 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. */ int[] workspace = new int [JpegConstants.DCTSIZE2]; /* work area for FDCT subroutine */ for (int bi = 0; bi < num_blocks; bi++, start_col += JpegConstants.DCTSIZE) { /* Load data into workspace, applying unsigned->signed conversion */ int workspaceIndex = 0; for (int elemr = 0; elemr < JpegConstants.DCTSIZE; elemr++) { for (int column = 0; column < JpegConstants.DCTSIZE; column++) { workspace[workspaceIndex] = (int)sample_data[start_row + elemr][start_col + column] - JpegConstants.CENTERJSAMPLE; workspaceIndex++; } } /* Perform the DCT */ if (m_useSlowMethod) jpeg_fdct_islow(workspace); else jpeg_fdct_ifast(workspace); /* Quantize/descale the coefficients, and store into coef_blocks[] */ for (int i = 0; i < JpegConstants.DCTSIZE2; i++) { int qval = m_divisors[quant_tbl_no][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; } } }
/// <summary> /// 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[]. /// </summary> public virtual void forward_DCT(int quant_tbl_no, byte[][] sample_data, JBLOCK[] coef_blocks, int start_row, int start_col, int num_blocks) { if (m_useFloatMethod) forwardDCTFloatImpl(quant_tbl_no, sample_data, coef_blocks, start_row, start_col, num_blocks); else forwardDCTImpl(quant_tbl_no, sample_data, coef_blocks, start_row, start_col, num_blocks); }
/// <summary> /// MCU decoding for DC successive approximation refinement scan. /// Note: we assume such scans can be multi-component, although the spec /// is not very clear on the point. /// </summary> private bool decode_mcu_DC_refine(JBLOCK[] MCU_data) { /* Process restart marker if needed; may have to suspend */ if (m_cinfo.m_restart_interval != 0) { if (m_restarts_to_go == 0) { if (!process_restart()) return false; } } /* Not worth the cycles to check insufficient_data here, * since we will not change the data anyway if we read zeroes. */ /* Load up working state */ int get_buffer; int bits_left; bitread_working_state br_state = new bitread_working_state(); BITREAD_LOAD_STATE(m_bitstate, out get_buffer, out bits_left, ref br_state); /* Outer loop handles each block in the MCU */ for (int blkn = 0; blkn < m_cinfo.m_blocks_in_MCU; blkn++) { /* Encoded data is simply the next bit of the two's-complement DC value */ if (!CHECK_BIT_BUFFER(ref br_state, 1, ref get_buffer, ref bits_left)) return false; if (GET_BITS(1, get_buffer, ref bits_left) != 0) { /* 1 in the bit position being coded */ MCU_data[blkn][0] = (short)((ushort)MCU_data[blkn][0] | (ushort)(1 << m_cinfo.m_Al)); } /* Note: since we use |=, repeating the assignment later is safe */ } /* Completed MCU, so update state */ BITREAD_SAVE_STATE(ref m_bitstate, get_buffer, bits_left); /* Account for restart interval (no-op if not using restarts) */ m_restarts_to_go--; return true; }
/// <summary> /// MCU encoding for AC successive approximation refinement scan. /// </summary> private bool encode_mcu_AC_refine(JBLOCK[][] MCU_data) { /* Emit restart marker if needed */ if (m_cinfo.m_restart_interval != 0) { if (m_restarts_to_go == 0) emit_restart(m_next_restart_num); } /* Encode the MCU data block */ /* It is convenient to make a pre-pass to determine the transformed * coefficients' absolute values and the EOB position. */ int EOB = 0; int[] absvalues = new int[JpegConstants.DCTSIZE2]; for (int k = m_cinfo.m_Ss; k <= m_cinfo.m_Se; k++) { int temp = MCU_data[0][0][JpegUtils.jpeg_natural_order[k]]; /* We must apply the point transform by Al. For AC coefficients this * is an integer division with rounding towards 0. To do this portably * in C, we shift after obtaining the absolute value. */ if (temp < 0) temp = -temp; /* temp is abs value of input */ temp >>= m_cinfo.m_Al; /* apply the point transform */ absvalues[k] = temp; /* save abs value for main pass */ if (temp == 1) { /* EOB = index of last newly-nonzero coef */ EOB = k; } } /* Encode the AC coefficients per section G.1.2.3, fig. G.7 */ int r = 0; /* r = run length of zeros */ int BR = 0; /* BR = count of buffered bits added now */ int bitBufferOffset = m_BE; /* Append bits to buffer */ for (int k = m_cinfo.m_Ss; k <= m_cinfo.m_Se; k++) { int temp = absvalues[k]; if (temp == 0) { r++; continue; } /* Emit any required ZRLs, but not if they can be folded into EOB */ while (r > 15 && k <= EOB) { /* emit any pending EOBRUN and the BE correction bits */ emit_eobrun(); /* Emit ZRL */ emit_symbol(m_ac_tbl_no, 0xF0); r -= 16; /* Emit buffered correction bits that must be associated with ZRL */ emit_buffered_bits(bitBufferOffset, BR); bitBufferOffset = 0;/* BE bits are gone now */ BR = 0; } /* If the coef was previously nonzero, it only needs a correction bit. * NOTE: a straight translation of the spec's figure G.7 would suggest * that we also need to test r > 15. But if r > 15, we can only get here * if k > EOB, which implies that this coefficient is not 1. */ if (temp > 1) { /* The correction bit is the next bit of the absolute value. */ m_bit_buffer[bitBufferOffset + BR] = (char) (temp & 1); BR++; continue; } /* Emit any pending EOBRUN and the BE correction bits */ emit_eobrun(); /* Count/emit Huffman symbol for run length / number of bits */ emit_symbol(m_ac_tbl_no, (r << 4) + 1); /* Emit output bit for newly-nonzero coef */ temp = (MCU_data[0][0][JpegUtils.jpeg_natural_order[k]] < 0) ? 0 : 1; emit_bits(temp, 1); /* Emit buffered correction bits that must be associated with this code */ emit_buffered_bits(bitBufferOffset, BR); bitBufferOffset = 0;/* BE bits are gone now */ BR = 0; r = 0; /* reset zero run length */ } if (r > 0 || BR > 0) { /* If there are trailing zeroes, */ m_EOBRUN++; /* count an EOB */ m_BE += BR; /* concat my correction bits to older ones */ /* We force out the EOB if we risk either: * 1. overflow of the EOB counter; * 2. overflow of the correction bit buffer during the next MCU. */ if (m_EOBRUN == 0x7FFF || m_BE > (MAX_CORR_BITS - JpegConstants.DCTSIZE2 + 1)) emit_eobrun(); } /* Update restart-interval state too */ if (m_cinfo.m_restart_interval != 0) { if (m_restarts_to_go == 0) { m_restarts_to_go = m_cinfo.m_restart_interval; m_next_restart_num++; m_next_restart_num &= 7; } m_restarts_to_go--; } return true; }
public override bool encode_mcu(JBLOCK[][] MCU_data) { switch (m_MCUEncoder) { case MCUEncoder.mcu_DC_first_encoder: return encode_mcu_DC_first(MCU_data); case MCUEncoder.mcu_AC_first_encoder: return encode_mcu_AC_first(MCU_data); case MCUEncoder.mcu_DC_refine_encoder: return encode_mcu_DC_refine(MCU_data); case MCUEncoder.mcu_AC_refine_encoder: return encode_mcu_AC_refine(MCU_data); } m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_NOTIMPL); return false; }
// 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; } } }
/// <summary> /// Process some data. /// 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. /// /// NB: input_buf is ignored; it is likely to be a null pointer. /// </summary> public virtual bool compress_data(byte[][][] input_buf) { /* 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 */ int last_MCU_col = m_cinfo.m_MCUs_per_row - 1; int last_iMCU_row = m_cinfo.m_total_iMCU_rows - 1; JBLOCK[][] MCU_buffer = new JBLOCK[JpegConstants.C_MAX_BLOCKS_IN_MCU][]; 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; int blockcnt = (MCU_col_num < last_MCU_col) ? componentInfo.MCU_width : componentInfo.last_col_width; for (int yindex = 0; yindex < componentInfo.MCU_height; yindex++) { int xindex = 0; if (m_iMCU_row_num < last_iMCU_row || yindex + yoffset < componentInfo.last_row_height) { /* Fill in pointers to real blocks in this row */ for (xindex = 0; xindex < blockcnt; xindex++) { int bufLength = buffer[ci][yindex + yoffset].Length; int start = start_col + xindex; MCU_buffer[blkn] = new JBLOCK[bufLength - start]; for (int j = start; j < bufLength; j++) MCU_buffer[blkn][j - start] = buffer[ci][yindex + yoffset][j]; blkn++; } } else { /* At bottom of image, need a whole row of dummy blocks */ xindex = 0; } /* Fill in any dummy blocks needed in this row. * Dummy blocks are filled in the same way as in jccoefct.c: * all zeroes in the AC entries, DC entries equal to previous * block's DC value. The init routine has already zeroed the * AC entries, so we need only set the DC entries correctly. */ for (; xindex < componentInfo.MCU_width; xindex++) { MCU_buffer[blkn] = m_dummy_buffer[blkn]; MCU_buffer[blkn][0][0] = MCU_buffer[blkn - 1][0][0]; blkn++; } } } /* Try to write the MCU. */ if (!m_cinfo.m_entropy.encode_mcu(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; }
// There is always only one block per MCU private bool decode_mcu_AC_refine(JBLOCK[] MCU_data) { int p1 = 1 << m_cinfo.m_Al; /* 1 in the bit position being coded */ int m1 = -1 << m_cinfo.m_Al; /* -1 in the bit position being coded */ /* Process restart marker if needed; may have to suspend */ if (m_cinfo.m_restart_interval != 0) { if (m_restarts_to_go == 0) { if (!process_restart()) return false; } } /* If we've run out of data, don't modify the MCU. */ if (!m_insufficient_data) { /* Load up working state */ int get_buffer; int bits_left; bitread_working_state br_state = new bitread_working_state(); BITREAD_LOAD_STATE(m_bitstate, out get_buffer, out bits_left, ref br_state); int EOBRUN = m_saved.EOBRUN; /* only part of saved state we need */ /* If we are forced to suspend, we must undo the assignments to any newly * nonzero coefficients in the block, because otherwise we'd get confused * next time about which coefficients were already nonzero. * But we need not undo addition of bits to already-nonzero coefficients; * instead, we can test the current bit to see if we already did it. */ int num_newnz = 0; int[] newnz_pos = new int[JpegConstants.DCTSIZE2]; /* initialize coefficient loop counter to start of band */ int k = m_cinfo.m_Ss; if (EOBRUN == 0) { for (; k <= m_cinfo.m_Se; k++) { int s; if (!HUFF_DECODE(out s, ref br_state, m_ac_derived_tbl, ref get_buffer, ref bits_left)) { undo_decode_mcu_AC_refine(MCU_data, newnz_pos, num_newnz); return false; } int r = s >> 4; s &= 15; if (s != 0) { if (s != 1) { /* size of new coef should always be 1 */ m_cinfo.WARNMS(J_MESSAGE_CODE.JWRN_HUFF_BAD_CODE); } if (!CHECK_BIT_BUFFER(ref br_state, 1, ref get_buffer, ref bits_left)) { undo_decode_mcu_AC_refine(MCU_data, newnz_pos, num_newnz); return false; } if (GET_BITS(1, get_buffer, ref bits_left) != 0) { /* newly nonzero coef is positive */ s = p1; } else { /* newly nonzero coef is negative */ s = m1; } } else { if (r != 15) { EOBRUN = 1 << r; /* EOBr, run length is 2^r + appended bits */ if (r != 0) { if (!CHECK_BIT_BUFFER(ref br_state, r, ref get_buffer, ref bits_left)) { undo_decode_mcu_AC_refine(MCU_data, newnz_pos, num_newnz); return false; } r = GET_BITS(r, get_buffer, ref bits_left); EOBRUN += r; } break; /* rest of block is handled by EOB logic */ } /* note s = 0 for processing ZRL */ } /* Advance over already-nonzero coefs and r still-zero coefs, * appending correction bits to the nonzeroes. A correction bit is 1 * if the absolute value of the coefficient must be increased. */ do { int blockIndex = JpegUtils.jpeg_natural_order[k]; short thiscoef = MCU_data[0][blockIndex]; if (thiscoef != 0) { if (!CHECK_BIT_BUFFER(ref br_state, 1, ref get_buffer, ref bits_left)) { undo_decode_mcu_AC_refine(MCU_data, newnz_pos, num_newnz); return false; } if (GET_BITS(1, get_buffer, ref bits_left) != 0) { if ((thiscoef & p1) == 0) { /* do nothing if already set it */ if (thiscoef >= 0) MCU_data[0][blockIndex] += (short)p1; else MCU_data[0][blockIndex] += (short)m1; } } } else { if (--r < 0) break; /* reached target zero coefficient */ } k++; } while (k <= m_cinfo.m_Se); if (s != 0) { int pos = JpegUtils.jpeg_natural_order[k]; /* Output newly nonzero coefficient */ MCU_data[0][pos] = (short)s; /* Remember its position in case we have to suspend */ newnz_pos[num_newnz++] = pos; } } } if (EOBRUN > 0) { /* Scan any remaining coefficient positions after the end-of-band * (the last newly nonzero coefficient, if any). Append a correction * bit to each already-nonzero coefficient. A correction bit is 1 * if the absolute value of the coefficient must be increased. */ for (; k <= m_cinfo.m_Se; k++) { int blockIndex = JpegUtils.jpeg_natural_order[k]; short thiscoef = MCU_data[0][blockIndex]; if (thiscoef != 0) { if (!CHECK_BIT_BUFFER(ref br_state, 1, ref get_buffer, ref bits_left)) { //undo_decode_mcu_AC_refine(MCU_data[0], newnz_pos, num_newnz); undo_decode_mcu_AC_refine(MCU_data, newnz_pos, num_newnz); return false; } if (GET_BITS(1, get_buffer, ref bits_left) != 0) { if ((thiscoef & p1) == 0) { /* do nothing if already changed it */ if (thiscoef >= 0) MCU_data[0][blockIndex] += (short)p1; else MCU_data[0][blockIndex] += (short)m1; } } } } /* Count one block completed in EOB run */ EOBRUN--; } /* Completed MCU, so update state */ BITREAD_SAVE_STATE(ref m_bitstate, get_buffer, bits_left); m_saved.EOBRUN = EOBRUN; /* only part of saved state we need */ } /* Account for restart interval (no-op if not using restarts) */ m_restarts_to_go--; return true; }
/// <summary> /// MCU decoding for AC initial scan (either spectral selection, /// or first pass of successive approximation). /// </summary> private bool decode_mcu_AC_first(JBLOCK[] MCU_data) { /* Process restart marker if needed; may have to suspend */ if (m_cinfo.m_restart_interval != 0) { if (m_restarts_to_go == 0) { if (!process_restart()) return false; } } /* If we've run out of data, just leave the MCU set to zeroes. * This way, we return uniform gray for the remainder of the segment. */ if (!m_insufficient_data) { /* Load up working state. * We can avoid loading/saving bitread state if in an EOB run. */ int EOBRUN = m_saved.EOBRUN; /* only part of saved state we need */ /* There is always only one block per MCU */ if (EOBRUN > 0) { /* if it's a band of zeroes... */ /* ...process it now (we do nothing) */ EOBRUN--; } else { int get_buffer; int bits_left; bitread_working_state br_state = new bitread_working_state(); BITREAD_LOAD_STATE(m_bitstate, out get_buffer, out bits_left, ref br_state); for (int k = m_cinfo.m_Ss; k <= m_cinfo.m_Se; k++) { int s; if (!HUFF_DECODE(out s, ref br_state, m_ac_derived_tbl, ref get_buffer, ref bits_left)) return false; int r = s >> 4; s &= 15; if (s != 0) { k += r; if (!CHECK_BIT_BUFFER(ref br_state, s, ref get_buffer, ref bits_left)) return false; r = GET_BITS(s, get_buffer, ref bits_left); s = HUFF_EXTEND(r, s); /* Scale and output coefficient in natural (dezigzagged) order */ MCU_data[0][JpegUtils.jpeg_natural_order[k]] = (short)(s << m_cinfo.m_Al); } else { if (r == 15) { /* ZRL */ k += 15; /* skip 15 zeroes in band */ } else { /* EOBr, run length is 2^r + appended bits */ EOBRUN = 1 << r; if (r != 0) { /* EOBr, r > 0 */ if (!CHECK_BIT_BUFFER(ref br_state, r, ref get_buffer, ref bits_left)) return false; r = GET_BITS(r, get_buffer, ref bits_left); EOBRUN += r; } EOBRUN--; /* this band is processed at this moment */ break; /* force end-of-band */ } } } BITREAD_SAVE_STATE(ref m_bitstate, get_buffer, bits_left); } /* Completed MCU, so update state */ m_saved.EOBRUN = EOBRUN; /* only part of saved state we need */ } /* Account for restart interval (no-op if not using restarts) */ m_restarts_to_go--; return true; }
/// <summary> /// MCU encoding for DC successive approximation refinement scan. /// Note: we assume such scans can be multi-component, although the spec /// is not very clear on the point. /// </summary> private bool encode_mcu_DC_refine(JBLOCK[][] MCU_data) { /* Emit restart marker if needed */ if (m_cinfo.m_restart_interval != 0) { if (m_restarts_to_go == 0) emit_restart(m_next_restart_num); } /* Encode the MCU data blocks */ for (int blkn = 0; blkn < m_cinfo.m_blocks_in_MCU; blkn++) { /* We simply emit the Al'th bit of the DC coefficient value. */ int temp = MCU_data[blkn][0][0]; emit_bits(temp >> m_cinfo.m_Al, 1); } /* Update restart-interval state too */ if (m_cinfo.m_restart_interval != 0) { if (m_restarts_to_go == 0) { m_restarts_to_go = m_cinfo.m_restart_interval; m_next_restart_num++; m_next_restart_num &= 7; } m_restarts_to_go--; } return true; }
/* * Huffman MCU decoding. * Each of these routines decodes and returns one MCU's worth of * Huffman-compressed coefficients. * The coefficients are reordered from zigzag order into natural array order, * but are not dequantized. * * The i'th block of the MCU is stored into the block pointed to by * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER. * * We return false if data source requested suspension. In that case no * changes have been made to permanent state. (Exception: some output * coefficients may already have been assigned. This is harmless for * spectral selection, since we'll just re-assign them on the next call. * Successive approximation AC refinement has to be more careful, however.) */ /// <summary> /// MCU decoding for DC initial scan (either spectral selection, /// or first pass of successive approximation). /// </summary> private bool decode_mcu_DC_first(JBLOCK[] MCU_data) { /* Process restart marker if needed; may have to suspend */ if (m_cinfo.m_restart_interval != 0) { if (m_restarts_to_go == 0) { if (!process_restart()) return false; } } /* If we've run out of data, just leave the MCU set to zeroes. * This way, we return uniform gray for the remainder of the segment. */ if (!m_insufficient_data) { /* Load up working state */ int get_buffer; int bits_left; bitread_working_state br_state = new bitread_working_state(); BITREAD_LOAD_STATE(m_bitstate, out get_buffer, out bits_left, ref br_state); savable_state state = new savable_state(); state.Assign(m_saved); /* Outer loop handles each block in the MCU */ for (int blkn = 0; blkn < m_cinfo.m_blocks_in_MCU; blkn++) { int ci = m_cinfo.m_MCU_membership[blkn]; /* Decode a single block's worth of coefficients */ /* Section F.2.2.1: decode the DC coefficient difference */ int s; if (!HUFF_DECODE(out s, ref br_state, m_derived_tbls[m_cinfo.Comp_info[m_cinfo.m_cur_comp_info[ci]].Dc_tbl_no], ref get_buffer, ref bits_left)) return false; if (s != 0) { if (!CHECK_BIT_BUFFER(ref br_state, s, ref get_buffer, ref bits_left)) return false; int r = GET_BITS(s, get_buffer, ref bits_left); s = HUFF_EXTEND(r, s); } /* Convert DC difference to actual value, update last_dc_val */ s += state.last_dc_val[ci]; state.last_dc_val[ci] = s; /* Scale and output the coefficient (assumes jpeg_natural_order[0]=0) */ MCU_data[blkn][0] = (short)(s << m_cinfo.m_Al); } /* Completed MCU, so update state */ BITREAD_SAVE_STATE(ref m_bitstate, get_buffer, bits_left); m_saved.Assign(state); } /* Account for restart interval (no-op if not using restarts) */ m_restarts_to_go--; return true; }
/// <summary> /// MCU encoding for AC initial scan (either spectral selection, /// or first pass of successive approximation). /// </summary> private bool encode_mcu_AC_first(JBLOCK[][] MCU_data) { /* Emit restart marker if needed */ if (m_cinfo.m_restart_interval != 0) { if (m_restarts_to_go == 0) emit_restart(m_next_restart_num); } /* Encode the AC coefficients per section G.1.2.2, fig. G.3 */ /* r = run length of zeros */ int r = 0; for (int k = m_cinfo.m_Ss; k <= m_cinfo.m_Se; k++) { int temp = MCU_data[0][0][JpegUtils.jpeg_natural_order[k]]; if (temp == 0) { r++; continue; } /* We must apply the point transform by Al. For AC coefficients this * is an integer division with rounding towards 0. To do this portably * in C, we shift after obtaining the absolute value; so the code is * interwoven with finding the abs value (temp) and output bits (temp2). */ int temp2; if (temp < 0) { temp = -temp; /* temp is abs value of input */ temp >>= m_cinfo.m_Al; /* apply the point transform */ /* For a negative coef, want temp2 = bitwise complement of abs(coef) */ temp2 = ~temp; } else { temp >>= m_cinfo.m_Al; /* apply the point transform */ temp2 = temp; } /* Watch out for case that nonzero coef is zero after point transform */ if (temp == 0) { r++; continue; } /* Emit any pending EOBRUN */ if (m_EOBRUN > 0) emit_eobrun(); /* if run length > 15, must emit special run-length-16 codes (0xF0) */ while (r > 15) { emit_symbol(m_ac_tbl_no, 0xF0); r -= 16; } /* Find the number of bits needed for the magnitude of the coefficient */ int nbits = 1; /* there must be at least one 1 bit */ while ((temp >>= 1) != 0) nbits++; /* Check for out-of-range coefficient values */ if (nbits > MAX_HUFFMAN_COEF_BITS) m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_BAD_DCT_COEF); /* Count/emit Huffman symbol for run length / number of bits */ emit_symbol(m_ac_tbl_no, (r << 4) + nbits); /* Emit that number of bits of the value, if positive, */ /* or the complement of its magnitude, if negative. */ emit_bits(temp2, nbits); r = 0; /* reset zero run length */ } if (r > 0) { /* If there are trailing zeroes, */ m_EOBRUN++; /* count an EOB */ if (m_EOBRUN == 0x7FFF) emit_eobrun(); /* force it out to avoid overflow */ } /* Update restart-interval state too */ if (m_cinfo.m_restart_interval != 0) { if (m_restarts_to_go == 0) { m_restarts_to_go = m_cinfo.m_restart_interval; m_next_restart_num++; m_next_restart_num &= 7; } m_restarts_to_go--; } return true; }
/// <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; }
/// <summary> /// MCU encoding for DC initial scan (either spectral selection, /// or first pass of successive approximation). /// </summary> private bool encode_mcu_DC_first(JBLOCK[][] MCU_data) { /* Emit restart marker if needed */ if (m_cinfo.m_restart_interval != 0) { if (m_restarts_to_go == 0) emit_restart(m_next_restart_num); } /* Encode the MCU data blocks */ for (int blkn = 0; blkn < m_cinfo.m_blocks_in_MCU; blkn++) { /* Compute the DC value after the required point transform by Al. * This is simply an arithmetic right shift. */ int temp2 = IRIGHT_SHIFT(MCU_data[blkn][0][0], m_cinfo.m_Al); /* DC differences are figured on the point-transformed values. */ int ci = m_cinfo.m_MCU_membership[blkn]; int temp = temp2 - m_last_dc_val[ci]; m_last_dc_val[ci] = temp2; /* Encode the DC coefficient difference per section G.1.2.1 */ temp2 = temp; if (temp < 0) { /* temp is abs value of input */ temp = -temp; /* For a negative input, want temp2 = bitwise complement of abs(input) */ /* This code assumes we are on a two's complement machine */ temp2--; } /* Find the number of bits needed for the magnitude of the coefficient */ int nbits = 0; while (temp != 0) { nbits++; temp >>= 1; } /* Check for out-of-range coefficient values. * Since we're encoding a difference, the range limit is twice as much. */ if (nbits > MAX_HUFFMAN_COEF_BITS + 1) m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_BAD_DCT_COEF); /* Count/emit the Huffman-coded symbol for the number of bits */ emit_symbol(m_cinfo.Component_info[m_cinfo.m_cur_comp_info[ci]].Dc_tbl_no, nbits); /* Emit that number of bits of the value, if positive, */ /* or the complement of its magnitude, if negative. */ if (nbits != 0) { /* emit_bits rejects calls with size 0 */ emit_bits(temp2, nbits); } } /* Update restart-interval state too */ if (m_cinfo.m_restart_interval != 0) { if (m_restarts_to_go == 0) { m_restarts_to_go = m_cinfo.m_restart_interval; m_next_restart_num++; m_next_restart_num &= 7; } m_restarts_to_go--; } return true; }
private byte[] DecodeGroup(JBLOCK block, int[] @group) { return(Hash(block, @group)); }
public abstract bool decode_mcu(JBLOCK[] MCU_data);
/// <summary> /// Consume input data and store it in the full-image coefficient buffer. /// We read as much as one fully interleaved MCU row ("iMCU" row) per call, /// ie, v_samp_factor block rows for each component in the scan. /// </summary> public ReadResult consume_data() { if (m_useDummyConsumeData) { return(ReadResult.JPEG_SUSPENDED); /* Always indicate nothing was done */ } JBLOCK[][][] buffer = new JBLOCK[JpegConstants.MAX_COMPS_IN_SCAN][][]; /* Align the virtual buffers for the components used in this scan. */ 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]]; buffer[ci] = m_whole_image[componentInfo.Component_index].Access( m_cinfo.m_input_iMCU_row * componentInfo.V_samp_factor, componentInfo.V_samp_factor); /* Note: entropy decoder expects buffer to be zeroed, * but this is handled automatically by the memory manager * because we requested a pre-zeroed array. */ } /* 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.Comp_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++) { m_MCU_buffer[blkn] = buffer[ci][yindex + yoffset][start_col + xindex]; blkn++; } } } /* Try to fetch the MCU. */ if (!m_cinfo.m_entropy.decode_mcu(m_MCU_buffer)) { /* Suspension forced; update state counters and exit */ m_MCU_vert_offset = yoffset; m_MCU_ctr = MCU_col_num; return(ReadResult.JPEG_SUSPENDED); } } /* Completed an MCU row, but perhaps not an iMCU row */ m_MCU_ctr = 0; } /* Completed the iMCU row, advance counters for next one */ m_cinfo.m_input_iMCU_row++; if (m_cinfo.m_input_iMCU_row < m_cinfo.m_total_iMCU_rows) { start_iMCU_row(); return(ReadResult.JPEG_ROW_COMPLETED); } /* Completed the scan */ m_cinfo.m_inputctl.finish_input_pass(); return(ReadResult.JPEG_SCAN_COMPLETED); }
// This version is used for floating-point DCT implementations. private void forwardDCTFloatImpl(int quant_tbl_no, 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[] workspace = new float [JpegConstants.DCTSIZE2]; /* work area for FDCT subroutine */ for (int bi = 0; bi < num_blocks; bi++, start_col += JpegConstants.DCTSIZE) { /* Load data into workspace, applying unsigned->signed conversion */ int workspaceIndex = 0; for (int elemr = 0; elemr < JpegConstants.DCTSIZE; elemr++) { for (int column = 0; column < JpegConstants.DCTSIZE; column++) { workspace[workspaceIndex] = (float)((int)sample_data[start_row + elemr][start_col + column] - JpegConstants.CENTERJSAMPLE); workspaceIndex++; } } /* Perform the DCT */ jpeg_fdct_float(workspace); /* 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] * m_float_divisors[quant_tbl_no][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); } } }
/// <summary> /// Variant of decompress_data for use when doing block smoothing. /// </summary> private ReadResult decompress_smooth_data(ComponentBuffer[] output_buf) { /* Force some input to be done if we are getting ahead of the input. */ while (m_cinfo.m_input_scan_number <= m_cinfo.m_output_scan_number && !m_cinfo.m_inputctl.EOIReached()) { if (m_cinfo.m_input_scan_number == m_cinfo.m_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. */ int delta = (m_cinfo.m_Ss == 0) ? 1 : 0; if (m_cinfo.m_input_iMCU_row > m_cinfo.m_output_iMCU_row + delta) { break; } } if (m_cinfo.m_inputctl.consume_input() == ReadResult.JPEG_SUSPENDED) { return(ReadResult.JPEG_SUSPENDED); } } int last_iMCU_row = m_cinfo.m_total_iMCU_rows - 1; /* OK, output from the virtual arrays. */ for (int ci = 0; ci < m_cinfo.m_num_components; ci++) { jpeg_component_info componentInfo = m_cinfo.Comp_info[ci]; /* Don't bother to IDCT an uninteresting component. */ if (!componentInfo.component_needed) { continue; } int block_rows; int access_rows; bool last_row; /* Count non-dummy DCT block rows in this iMCU row. */ if (m_cinfo.m_output_iMCU_row < last_iMCU_row) { block_rows = componentInfo.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 = componentInfo.height_in_blocks % componentInfo.V_samp_factor; if (block_rows == 0) { block_rows = componentInfo.V_samp_factor; } access_rows = block_rows; /* this iMCU row only */ last_row = true; } /* Align the virtual buffer for this component. */ JBLOCK[][] buffer = null; bool first_row; int bufferRowOffset = 0; if (m_cinfo.m_output_iMCU_row > 0) { access_rows += componentInfo.V_samp_factor; /* prior iMCU row too */ buffer = m_whole_image[ci].Access((m_cinfo.m_output_iMCU_row - 1) * componentInfo.V_samp_factor, access_rows); bufferRowOffset = componentInfo.V_samp_factor; /* point to current iMCU row */ first_row = false; } else { buffer = m_whole_image[ci].Access(0, access_rows); first_row = true; } /* Fetch component-dependent info */ int coefBitsOffset = ci * SAVED_COEFS; int Q00 = componentInfo.quant_table.quantval[0]; int Q01 = componentInfo.quant_table.quantval[Q01_POS]; int Q10 = componentInfo.quant_table.quantval[Q10_POS]; int Q20 = componentInfo.quant_table.quantval[Q20_POS]; int Q11 = componentInfo.quant_table.quantval[Q11_POS]; int Q02 = componentInfo.quant_table.quantval[Q02_POS]; int outputIndex = ci; /* Loop over all DCT blocks to be processed. */ for (int block_row = 0; block_row < block_rows; block_row++) { int bufferIndex = bufferRowOffset + block_row; int prev_block_row = 0; if (first_row && block_row == 0) { prev_block_row = bufferIndex; } else { prev_block_row = bufferIndex - 1; } int next_block_row = 0; if (last_row && block_row == block_rows - 1) { next_block_row = bufferIndex; } else { next_block_row = bufferIndex + 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 = buffer[prev_block_row][0][0]; int DC2 = DC1; int DC3 = DC1; int DC4 = buffer[bufferIndex][0][0]; int DC5 = DC4; int DC6 = DC4; int DC7 = buffer[next_block_row][0][0]; int DC8 = DC7; int DC9 = DC7; int output_col = 0; int last_block_column = componentInfo.Width_in_blocks - 1; for (int block_num = 0; block_num <= last_block_column; block_num++) { /* Fetch current DCT block into workspace so we can modify it. */ JBLOCK workspace = new JBLOCK(); Buffer.BlockCopy(buffer[bufferIndex][0].data, 0, workspace.data, 0, workspace.data.Length * sizeof(short)); /* Update DC values */ if (block_num < last_block_column) { DC3 = buffer[prev_block_row][1][0]; DC6 = buffer[bufferIndex][1][0]; DC9 = buffer[next_block_row][1][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 = m_coef_bits_latch[m_coef_bits_savedOffset + coefBitsOffset + 1]; if (Al != 0 && workspace[1] == 0) { int pred; int num = 36 * Q00 * (DC4 - DC6); if (num >= 0) { pred = ((Q01 << 7) + num) / (Q01 << 8); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } } else { pred = ((Q01 << 7) - num) / (Q01 << 8); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } pred = -pred; } workspace[1] = (short)pred; } /* AC10 */ Al = m_coef_bits_latch[m_coef_bits_savedOffset + coefBitsOffset + 2]; if (Al != 0 && workspace[8] == 0) { int pred; int num = 36 * Q00 * (DC2 - DC8); if (num >= 0) { pred = ((Q10 << 7) + num) / (Q10 << 8); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } } else { pred = ((Q10 << 7) - num) / (Q10 << 8); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } pred = -pred; } workspace[8] = (short)pred; } /* AC20 */ Al = m_coef_bits_latch[m_coef_bits_savedOffset + coefBitsOffset + 3]; if (Al != 0 && workspace[16] == 0) { int pred; int num = 9 * Q00 * (DC2 + DC8 - 2 * DC5); if (num >= 0) { pred = ((Q20 << 7) + num) / (Q20 << 8); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } } else { pred = ((Q20 << 7) - num) / (Q20 << 8); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } pred = -pred; } workspace[16] = (short)pred; } /* AC11 */ Al = m_coef_bits_latch[m_coef_bits_savedOffset + coefBitsOffset + 4]; if (Al != 0 && workspace[9] == 0) { int pred; int num = 5 * Q00 * (DC1 - DC3 - DC7 + DC9); if (num >= 0) { pred = ((Q11 << 7) + num) / (Q11 << 8); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } } else { pred = ((Q11 << 7) - num) / (Q11 << 8); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } pred = -pred; } workspace[9] = (short)pred; } /* AC02 */ Al = m_coef_bits_latch[m_coef_bits_savedOffset + coefBitsOffset + 5]; if (Al != 0 && workspace[2] == 0) { int pred; int num = 9 * Q00 * (DC4 + DC6 - 2 * DC5); if (num >= 0) { pred = ((Q02 << 7) + num) / (Q02 << 8); if (Al > 0 && pred >= (1 << Al)) { pred = (1 << Al) - 1; } } else { pred = ((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 */ m_cinfo.m_idct.inverse(componentInfo.Component_index, workspace.data, output_buf[outputIndex], 0, output_col); /* Advance for next column */ DC1 = DC2; DC2 = DC3; DC4 = DC5; DC5 = DC6; DC7 = DC8; DC8 = DC9; bufferIndex++; prev_block_row++; next_block_row++; output_col += componentInfo.DCT_scaled_size; } outputIndex += componentInfo.DCT_scaled_size; } } m_cinfo.m_output_iMCU_row++; if (m_cinfo.m_output_iMCU_row < m_cinfo.m_total_iMCU_rows) { return(ReadResult.JPEG_ROW_COMPLETED); } return(ReadResult.JPEG_SCAN_COMPLETED); }
/// <summary> /// Consume input data and store it in the full-image coefficient buffer. /// We read as much as one fully interleaved MCU row ("iMCU" row) per call, /// ie, v_samp_factor block rows for each component in the scan. /// </summary> public ReadResult consume_data() { if (m_useDummyConsumeData) return ReadResult.JPEG_SUSPENDED; /* Always indicate nothing was done */ JBLOCK[][][] buffer = new JBLOCK[JpegConstants.MAX_COMPS_IN_SCAN][][]; /* Align the virtual buffers for the components used in this scan. */ 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]]; buffer[ci] = m_whole_image[componentInfo.Component_index].Access( m_cinfo.m_input_iMCU_row * componentInfo.V_samp_factor, componentInfo.V_samp_factor); /* Note: entropy decoder expects buffer to be zeroed, * but this is handled automatically by the memory manager * because we requested a pre-zeroed array. */ } /* 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.Comp_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++) { m_MCU_buffer[blkn] = buffer[ci][yindex + yoffset][start_col + xindex]; blkn++; } } } /* Try to fetch the MCU. */ if (!m_cinfo.m_entropy.decode_mcu(m_MCU_buffer)) { /* Suspension forced; update state counters and exit */ m_MCU_vert_offset = yoffset; m_MCU_ctr = MCU_col_num; return ReadResult.JPEG_SUSPENDED; } } /* Completed an MCU row, but perhaps not an iMCU row */ m_MCU_ctr = 0; } /* Completed the iMCU row, advance counters for next one */ m_cinfo.m_input_iMCU_row++; if (m_cinfo.m_input_iMCU_row < m_cinfo.m_total_iMCU_rows) { start_iMCU_row(); return ReadResult.JPEG_ROW_COMPLETED; } /* Completed the scan */ m_cinfo.m_inputctl.finish_input_pass(); return ReadResult.JPEG_SCAN_COMPLETED; }
/// <summary> /// Encode and output one MCU's worth of Huffman-compressed coefficients. /// </summary> private bool encode_mcu_huff(JBLOCK[][] MCU_data) { /* Load up working state */ savable_state state; state = m_saved; /* Emit restart marker if needed */ if (m_cinfo.m_restart_interval != 0) { if (m_restarts_to_go == 0) { if (!emit_restart(state, m_next_restart_num)) return false; } } /* Encode the MCU data blocks */ for (int blkn = 0; blkn < m_cinfo.m_blocks_in_MCU; blkn++) { int ci = m_cinfo.m_MCU_membership[blkn]; if (!encode_one_block(state, MCU_data[blkn][0].data, state.last_dc_val[ci], m_dc_derived_tbls[m_cinfo.Component_info[m_cinfo.m_cur_comp_info[ci]].Dc_tbl_no], m_ac_derived_tbls[m_cinfo.Component_info[m_cinfo.m_cur_comp_info[ci]].Ac_tbl_no])) { return false; } /* Update last_dc_val */ state.last_dc_val[ci] = MCU_data[blkn][0][0]; } /* Completed MCU, so update state */ m_saved = state; /* Update restart-interval state too */ if (m_cinfo.m_restart_interval != 0) { if (m_restarts_to_go == 0) { m_restarts_to_go = m_cinfo.m_restart_interval; m_next_restart_num++; m_next_restart_num &= 7; } m_restarts_to_go--; } return true; }
public jpeg_d_coef_controller(jpeg_decompress_struct cinfo, bool need_full_buffer) { m_cinfo = cinfo; /* Create the coefficient buffer. */ if (need_full_buffer) { /* Allocate a full-image virtual 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.m_num_components; ci++) { m_whole_image[ci] = jpeg_common_struct.CreateBlocksArray( JpegUtils.jround_up(cinfo.Comp_info[ci].Width_in_blocks, cinfo.Comp_info[ci].H_samp_factor), JpegUtils.jround_up(cinfo.Comp_info[ci].height_in_blocks, cinfo.Comp_info[ci].V_samp_factor)); m_whole_image[ci].ErrorProcessor = cinfo; } m_useDummyConsumeData = false; m_decompressor = DecompressorType.Ordinary; m_coef_arrays = m_whole_image; /* link to virtual arrays */ } else { /* We only need a single-MCU buffer. */ JBLOCK[] buffer = new JBLOCK[JpegConstants.D_MAX_BLOCKS_IN_MCU]; for (int i = 0; i < JpegConstants.D_MAX_BLOCKS_IN_MCU; i++) { buffer[i] = new JBLOCK(); for (int ii = 0; ii < buffer[i].data.Length; ii++) buffer[i].data[ii] = -12851; m_MCU_buffer[i] = buffer[i]; } m_useDummyConsumeData = true; m_decompressor = DecompressorType.OnePass; m_coef_arrays = null; /* flag for no virtual arrays */ } }
/// <summary> /// Process some data. /// 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. /// /// NB: input_buf is ignored; it is likely to be a null pointer. /// </summary> public virtual bool compress_data(byte[][][] input_buf) { /* 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 */ int last_MCU_col = m_cinfo.m_MCUs_per_row - 1; int last_iMCU_row = m_cinfo.m_total_iMCU_rows - 1; JBLOCK[][] MCU_buffer = new JBLOCK[JpegConstants.C_MAX_BLOCKS_IN_MCU][]; 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; int blockcnt = (MCU_col_num < last_MCU_col) ? componentInfo.MCU_width : componentInfo.last_col_width; for (int yindex = 0; yindex < componentInfo.MCU_height; yindex++) { int xindex = 0; if (m_iMCU_row_num < last_iMCU_row || yindex + yoffset < componentInfo.last_row_height) { /* Fill in pointers to real blocks in this row */ for (xindex = 0; xindex < blockcnt; xindex++) { int bufLength = buffer[ci][yindex + yoffset].Length; int start = start_col + xindex; MCU_buffer[blkn] = new JBLOCK[bufLength - start]; for (int j = start; j < bufLength; j++) { MCU_buffer[blkn][j - start] = buffer[ci][yindex + yoffset][j]; } blkn++; } } else { /* At bottom of image, need a whole row of dummy blocks */ xindex = 0; } /* Fill in any dummy blocks needed in this row. * Dummy blocks are filled in the same way as in jccoefct.c: * all zeroes in the AC entries, DC entries equal to previous * block's DC value. The init routine has already zeroed the * AC entries, so we need only set the DC entries correctly. */ for (; xindex < componentInfo.MCU_width; xindex++) { MCU_buffer[blkn] = m_dummy_buffer[blkn]; MCU_buffer[blkn][0][0] = MCU_buffer[blkn - 1][0][0]; blkn++; } } } /* Try to write the MCU. */ if (!m_cinfo.m_entropy.encode_mcu(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); }