/* * These are the routines invoked by the control routines to do * the actual upsampling/conversion. One row group is processed per call. * * Note: since we may be writing directly into application-supplied buffers, * we have to be honest about the output width; we can't assume the buffer * has been rounded up to an even width. */ /// <summary> /// Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical. /// </summary> private void h2v1_merged_upsample(ComponentBuffer[] input_buf, int in_row_group_ctr, byte[][] output_buf, int outRow) { int inputIndex0 = 0; int inputIndex1 = 0; int inputIndex2 = 0; int outputIndex = 0; byte[] limit = m_cinfo.m_sample_range_limit; int limitOffset = m_cinfo.m_sampleRangeLimitOffset; /* Loop for each pair of output pixels */ for (int col = m_cinfo.m_output_width >> 1; col > 0; col--) { /* Do the chroma part of the calculation */ int cb = input_buf[1][in_row_group_ctr][inputIndex1]; inputIndex1++; int cr = input_buf[2][in_row_group_ctr][inputIndex2]; inputIndex2++; int cred = m_Cr_r_tab[cr]; int cgreen = JpegUtils.RIGHT_SHIFT(m_Cb_g_tab[cb] + m_Cr_g_tab[cr], SCALEBITS); int cblue = m_Cb_b_tab[cb]; /* Fetch 2 Y values and emit 2 pixels */ int y = input_buf[0][in_row_group_ctr][inputIndex0]; inputIndex0++; output_buf[outRow][outputIndex + JpegConstants.RGB_RED] = limit[limitOffset + y + cred]; output_buf[outRow][outputIndex + JpegConstants.RGB_GREEN] = limit[limitOffset + y + cgreen]; output_buf[outRow][outputIndex + JpegConstants.RGB_BLUE] = limit[limitOffset + y + cblue]; outputIndex += JpegConstants.RGB_PIXELSIZE; y = input_buf[0][in_row_group_ctr][inputIndex0]; inputIndex0++; output_buf[outRow][outputIndex + JpegConstants.RGB_RED] = limit[limitOffset + y + cred]; output_buf[outRow][outputIndex + JpegConstants.RGB_GREEN] = limit[limitOffset + y + cgreen]; output_buf[outRow][outputIndex + JpegConstants.RGB_BLUE] = limit[limitOffset + y + cblue]; outputIndex += JpegConstants.RGB_PIXELSIZE; } /* If image width is odd, do the last output column separately */ if ((m_cinfo.m_output_width & 1) != 0) { int cb = input_buf[1][in_row_group_ctr][inputIndex1]; int cr = input_buf[2][in_row_group_ctr][inputIndex2]; int cred = m_Cr_r_tab[cr]; int cgreen = JpegUtils.RIGHT_SHIFT(m_Cb_g_tab[cb] + m_Cr_g_tab[cr], SCALEBITS); int cblue = m_Cb_b_tab[cb]; int y = input_buf[0][in_row_group_ctr][inputIndex0]; output_buf[outRow][outputIndex + JpegConstants.RGB_RED] = limit[limitOffset + y + cred]; output_buf[outRow][outputIndex + JpegConstants.RGB_GREEN] = limit[limitOffset + y + cgreen]; output_buf[outRow][outputIndex + JpegConstants.RGB_BLUE] = limit[limitOffset + y + cblue]; } }
/// <summary> /// Adobe-style YCCK->CMYK conversion. /// We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same /// conversion as above, while passing K (black) unchanged. /// We assume build_ycc_rgb_table has been called. /// </summary> private void YcckCmykConvert(ComponentBuffer[] input_buf, int input_row, byte[][] output_buf, int output_row, int num_rows) { var component0RowOffset = m_perComponentOffsets[0]; var component1RowOffset = m_perComponentOffsets[1]; var component2RowOffset = m_perComponentOffsets[2]; var component3RowOffset = m_perComponentOffsets[3]; var limit = m_cinfo.m_sample_range_limit; var limitOffset = m_cinfo.m_sampleRangeLimitOffset; var num_cols = m_cinfo.outputWidth; for (var row = 0; row < num_rows; row++) { var columnOffset = 0; for (var col = 0; col < num_cols; col++) { int y = input_buf[0][input_row + component0RowOffset][col]; int cb = input_buf[1][input_row + component1RowOffset][col]; int cr = input_buf[2][input_row + component2RowOffset][col]; /* Range-limiting is essential due to noise introduced by DCT losses, * and for extended gamut encodings (sYCC). */ output_buf[output_row + row][columnOffset] = limit[limitOffset + JpegConstants.MAXJSAMPLE - (y + m_Cr_r_tab[cr])]; /* red */ output_buf[output_row + row][columnOffset + 1] = limit[limitOffset + JpegConstants.MAXJSAMPLE - (y + JpegUtils.RIGHT_SHIFT(m_Cb_g_tab[cb] + m_Cr_g_tab[cr], SCALEBITS))]; /* green */ output_buf[output_row + row][columnOffset + 2] = limit[limitOffset + JpegConstants.MAXJSAMPLE - (y + m_Cb_b_tab[cb])]; /* blue */ /* K passes through unchanged */ /* don't need GETJSAMPLE here */ output_buf[output_row + row][columnOffset + 3] = input_buf[3][input_row + component3RowOffset][col]; columnOffset += 4; } input_row++; } }
private void YccRgbConvert(ComponentBuffer[] input_buf, int input_row, byte[][] output_buf, int output_row, int num_rows) { var component0RowOffset = m_perComponentOffsets[0]; var component1RowOffset = m_perComponentOffsets[1]; var component2RowOffset = m_perComponentOffsets[2]; var limit = m_cinfo.m_sample_range_limit; var limitOffset = m_cinfo.m_sampleRangeLimitOffset; for (var row = 0; row < num_rows; row++) { var columnOffset = 0; for (var col = 0; col < m_cinfo.outputWidth; col++) { int y = input_buf[0][input_row + component0RowOffset][col]; int cb = input_buf[1][input_row + component1RowOffset][col]; int cr = input_buf[2][input_row + component2RowOffset][col]; /* Range-limiting is essential due to noise introduced by DCT losses. * for extended gamut (sYCC) and wide gamut (bg-sYCC) encodings. */ output_buf[output_row + row][columnOffset + JpegConstants.RGB_RED] = limit[limitOffset + y + m_Cr_r_tab[cr]]; output_buf[output_row + row][columnOffset + JpegConstants.RGB_GREEN] = limit[limitOffset + y + JpegUtils.RIGHT_SHIFT(m_Cb_g_tab[cb] + m_Cr_g_tab[cr], SCALEBITS)]; output_buf[output_row + row][columnOffset + JpegConstants.RGB_BLUE] = limit[limitOffset + y + m_Cb_b_tab[cb]]; columnOffset += JpegConstants.RGB_PIXELSIZE; } input_row++; } }
/// <summary> /// Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical. /// </summary> private void H2V2MergedUpSample(ComponentBuffer[] input_buf, int in_row_group_ctr, byte[][] output_buf) { var inputRow00 = in_row_group_ctr * 2; var inputIndex00 = 0; var inputRow01 = (in_row_group_ctr * 2) + 1; var inputIndex01 = 0; var inputIndex1 = 0; var inputIndex2 = 0; var outIndex0 = 0; var outIndex1 = 0; var limit = m_cinfo.m_sample_range_limit; var limitOffset = m_cinfo.m_sampleRangeLimitOffset; /* Loop for each group of output pixels */ for (var col = m_cinfo.outputWidth >> 1; col > 0; col--) { /* Do the chroma part of the calculation */ int cb = input_buf[1][in_row_group_ctr][inputIndex1]; inputIndex1++; int cr = input_buf[2][in_row_group_ctr][inputIndex2]; inputIndex2++; var cred = m_Cr_r_tab[cr]; var cgreen = JpegUtils.RIGHT_SHIFT(m_Cb_g_tab[cb] + m_Cr_g_tab[cr], SCALEBITS); var cblue = m_Cb_b_tab[cb]; /* Fetch 4 Y values and emit 4 pixels */ int y = input_buf[0][inputRow00][inputIndex00]; inputIndex00++; output_buf[0][outIndex0 + JpegConstants.RGB_RED] = limit[limitOffset + y + cred]; output_buf[0][outIndex0 + JpegConstants.RGB_GREEN] = limit[limitOffset + y + cgreen]; output_buf[0][outIndex0 + JpegConstants.RGB_BLUE] = limit[limitOffset + y + cblue]; outIndex0 += JpegConstants.RGB_PIXELSIZE; y = input_buf[0][inputRow00][inputIndex00]; inputIndex00++; output_buf[0][outIndex0 + JpegConstants.RGB_RED] = limit[limitOffset + y + cred]; output_buf[0][outIndex0 + JpegConstants.RGB_GREEN] = limit[limitOffset + y + cgreen]; output_buf[0][outIndex0 + JpegConstants.RGB_BLUE] = limit[limitOffset + y + cblue]; outIndex0 += JpegConstants.RGB_PIXELSIZE; y = input_buf[0][inputRow01][inputIndex01]; inputIndex01++; output_buf[1][outIndex1 + JpegConstants.RGB_RED] = limit[limitOffset + y + cred]; output_buf[1][outIndex1 + JpegConstants.RGB_GREEN] = limit[limitOffset + y + cgreen]; output_buf[1][outIndex1 + JpegConstants.RGB_BLUE] = limit[limitOffset + y + cblue]; outIndex1 += JpegConstants.RGB_PIXELSIZE; y = input_buf[0][inputRow01][inputIndex01]; inputIndex01++; output_buf[1][outIndex1 + JpegConstants.RGB_RED] = limit[limitOffset + y + cred]; output_buf[1][outIndex1 + JpegConstants.RGB_GREEN] = limit[limitOffset + y + cgreen]; output_buf[1][outIndex1 + JpegConstants.RGB_BLUE] = limit[limitOffset + y + cblue]; outIndex1 += JpegConstants.RGB_PIXELSIZE; } /* If image width is odd, do the last output column separately */ if ((m_cinfo.outputWidth & 1) != 0) { int cb = input_buf[1][in_row_group_ctr][inputIndex1]; int cr = input_buf[2][in_row_group_ctr][inputIndex2]; var cred = m_Cr_r_tab[cr]; var cgreen = JpegUtils.RIGHT_SHIFT(m_Cb_g_tab[cb] + m_Cr_g_tab[cr], SCALEBITS); var cblue = m_Cb_b_tab[cb]; int y = input_buf[0][inputRow00][inputIndex00]; output_buf[0][outIndex0 + JpegConstants.RGB_RED] = limit[limitOffset + y + cred]; output_buf[0][outIndex0 + JpegConstants.RGB_GREEN] = limit[limitOffset + y + cgreen]; output_buf[0][outIndex0 + JpegConstants.RGB_BLUE] = limit[limitOffset + y + cblue]; y = input_buf[0][inputRow01][inputIndex01]; output_buf[1][outIndex1 + JpegConstants.RGB_RED] = limit[limitOffset + y + cred]; output_buf[1][outIndex1 + JpegConstants.RGB_GREEN] = limit[limitOffset + y + cgreen]; output_buf[1][outIndex1 + JpegConstants.RGB_BLUE] = limit[limitOffset + y + cblue]; } }