// Initialize tables for YCC->RGB colorspace conversion. // This is taken directly from jdcolor.cs; see that file for more info. static void build_ycc_rgb_table_upsample(jpeg_decompress cinfo) { my_upsampler_merge upsample = (my_upsampler_merge)cinfo.upsample; try { upsample.Cr_r_tab = new int[MAXJSAMPLE + 1]; upsample.Cb_b_tab = new int[MAXJSAMPLE + 1]; upsample.Cr_g_tab = new int[MAXJSAMPLE + 1]; upsample.Cb_g_tab = new int[MAXJSAMPLE + 1]; } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } for (int i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { // i is the actual input pixel value, in the range 0..MAXJSAMPLE // The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE // Cr=>R value is nearest int to 1.40200 * x upsample.Cr_r_tab[i] = (int)((FIX_140200 * x + ONE_HALF) >> SCALEBITS); // Cb=>B value is nearest int to 1.77200 * x upsample.Cb_b_tab[i] = (int)((FIX_177200 * x + ONE_HALF) >> SCALEBITS); // Cr=>G value is scaled-up -0.71414 * x upsample.Cr_g_tab[i] = (-FIX_071414) * x; // Cb=>G value is scaled-up -0.34414 * x // We also add in ONE_HALF so that need not do it in inner loop upsample.Cb_g_tab[i] = (-FIX_034414) * x + ONE_HALF; } }
// Control routine to do upsampling (and color conversion). // // The control routine just handles the row buffering considerations. // 2:1 vertical sampling case: may need a spare row. static void merged_2v_upsample(jpeg_decompress cinfo, byte[][][] input_buf, ref uint in_row_group_ctr, uint in_row_groups_avail, byte[][] output_buf, uint output_buf_offset, ref uint out_row_ctr, uint out_rows_avail) { my_upsampler_merge upsample = (my_upsampler_merge)cinfo.upsample; byte[][] work_ptrs = new byte[2][]; uint num_rows; // number of rows returned to caller if (upsample.spare_full) { // If we have a spare row saved from a previous cycle, just return it. Array.Copy(upsample.spare_row, output_buf[output_buf_offset + out_row_ctr], upsample.out_row_width); num_rows = 1; upsample.spare_full = false; } else { // Figure number of rows to return to caller. num_rows = 2; // Not more than the distance to the end of the image. if (num_rows > upsample.rows_to_go) { num_rows = upsample.rows_to_go; } // And not more than what the client can accept: out_rows_avail -= out_row_ctr; if (num_rows > out_rows_avail) { num_rows = out_rows_avail; } // Create output pointer array for upsampler. work_ptrs[0] = output_buf[output_buf_offset + out_row_ctr]; if (num_rows > 1) { work_ptrs[1] = output_buf[output_buf_offset + out_row_ctr + 1]; } else { work_ptrs[1] = upsample.spare_row; upsample.spare_full = true; } // Now do the upsampling. upsample.upmethod(cinfo, input_buf, in_row_group_ctr, work_ptrs, 0); } // Adjust counts out_row_ctr += num_rows; upsample.rows_to_go -= num_rows; // When the buffer is emptied, declare this input row group consumed if (!upsample.spare_full) { in_row_group_ctr++; } }
// Initialize for an upsampling pass. static void start_pass_merged_upsample(jpeg_decompress cinfo) { my_upsampler_merge upsample = (my_upsampler_merge)cinfo.upsample; // Mark the spare buffer empty upsample.spare_full = false; // Initialize total-height counter for detecting bottom of image upsample.rows_to_go = cinfo.output_height; }
// 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. // Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical. static void h2v1_merged_upsample(jpeg_decompress cinfo, byte[][][] input_buf, uint in_row_group_ctr, byte[][] output_buf, int output_buf_offset) { my_upsampler_merge upsample = (my_upsampler_merge)cinfo.upsample; // copy these pointers into registers if possible int[] Crrtab = upsample.Cr_r_tab; int[] Cbbtab = upsample.Cb_b_tab; int[] Crgtab = upsample.Cr_g_tab; int[] Cbgtab = upsample.Cb_g_tab; byte[] inptr0 = input_buf[0][in_row_group_ctr]; byte[] inptr1 = input_buf[1][in_row_group_ctr]; byte[] inptr2 = input_buf[2][in_row_group_ctr]; byte[] outptr = output_buf[output_buf_offset]; int inptr0_ind = 0, inptrX_ind = 0, outptr_ind = 0; // Loop for each pair of output pixels for (uint col = cinfo.output_width >> 1; col > 0; col--) { // Do the chroma part of the calculation int cb = inptr1[inptrX_ind]; int cr = inptr2[inptrX_ind]; inptrX_ind++; int cred = Crrtab[cr]; int cgreen = (int)((Cbgtab[cb] + Crgtab[cr]) >> SCALEBITS); int cblue = Cbbtab[cb]; // Fetch 2 Y values and emit 2 pixels int y = inptr0[inptr0_ind++]; int tmp = y + cred; outptr[outptr_ind + RGB_RED] = (byte)(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp)); tmp = y + cgreen; outptr[outptr_ind + RGB_GREEN] = (byte)(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp)); tmp = y + cblue; outptr[outptr_ind + RGB_BLUE] = (byte)(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp)); outptr_ind += RGB_PIXELSIZE; y = inptr0[inptr0_ind++]; tmp = y + cred; outptr[outptr_ind + RGB_RED] = (byte)(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp)); tmp = y + cgreen; outptr[outptr_ind + RGB_GREEN] = (byte)(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp)); tmp = y + cblue; outptr[outptr_ind + RGB_BLUE] = (byte)(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp)); outptr_ind = RGB_PIXELSIZE; } // If image width is odd, do the last output column separately if ((cinfo.output_width & 1) != 0) { int cb = inptr1[inptrX_ind]; int cr = inptr2[inptrX_ind]; int cred = Crrtab[cr]; int cgreen = (int)((Cbgtab[cb] + Crgtab[cr]) >> SCALEBITS); int cblue = Cbbtab[cb]; int y = inptr0[inptr0_ind]; int tmp = y + cred; outptr[outptr_ind + RGB_RED] = (byte)(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp)); tmp = y + cgreen; outptr[outptr_ind + RGB_GREEN] = (byte)(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp)); tmp = y + cblue; outptr[outptr_ind + RGB_BLUE] = (byte)(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp)); } }
// 1:1 vertical sampling case: much easier, never need a spare row. static void merged_1v_upsample(jpeg_decompress cinfo, byte[][][] input_buf, ref uint in_row_group_ctr, uint in_row_groups_avail, byte[][] output_buf, uint output_buf_offset, ref uint out_row_ctr, uint out_rows_avail) { my_upsampler_merge upsample = (my_upsampler_merge)cinfo.upsample; // Just do the upsampling. upsample.upmethod(cinfo, input_buf, in_row_group_ctr, output_buf, (int)(output_buf_offset + out_row_ctr)); // Adjust counts out_row_ctr++; in_row_group_ctr++; }
// Module initialization routine for merged upsampling/color conversion. // // NB: this is called under the conditions determined by use_merged_upsample() // in jdmaster.cs. That routine MUST correspond to the actual capabilities // of this module; no safety checks are made here. public static void jinit_merged_upsampler(jpeg_decompress cinfo) { my_upsampler_merge upsample = null; try { upsample = new my_upsampler_merge(); } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } cinfo.upsample = upsample; upsample.start_pass = start_pass_merged_upsample; #if UPSCALING_CONTEXT upsample.need_context_rows = false; #endif upsample.out_row_width = (uint)(cinfo.output_width * cinfo.out_color_components); if (cinfo.max_v_samp_factor == 2) { upsample.upsample = merged_2v_upsample; upsample.upmethod = h2v2_merged_upsample; // Allocate a spare row buffer try { upsample.spare_row = new byte[upsample.out_row_width]; } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } } else { upsample.upsample = merged_1v_upsample; upsample.upmethod = h2v1_merged_upsample; // No spare row needed upsample.spare_row = null; } build_ycc_rgb_table_upsample(cinfo); }
// Module initialization routine for merged upsampling/color conversion. // // NB: this is called under the conditions determined by use_merged_upsample() // in jdmaster.cs. That routine MUST correspond to the actual capabilities // of this module; no safety checks are made here. public static void jinit_merged_upsampler(jpeg_decompress cinfo) { my_upsampler_merge upsample=null; try { upsample=new my_upsampler_merge(); } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } cinfo.upsample=upsample; upsample.start_pass=start_pass_merged_upsample; #if UPSCALING_CONTEXT upsample.need_context_rows=false; #endif upsample.out_row_width=(uint)(cinfo.output_width*cinfo.out_color_components); if(cinfo.max_v_samp_factor==2) { upsample.upsample=merged_2v_upsample; upsample.upmethod=h2v2_merged_upsample; // Allocate a spare row buffer try { upsample.spare_row=new byte[upsample.out_row_width]; } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } } else { upsample.upsample=merged_1v_upsample; upsample.upmethod=h2v1_merged_upsample; // No spare row needed upsample.spare_row=null; } build_ycc_rgb_table_upsample(cinfo); }