// Initialize FDCT manager. static void jinit_forward_dct(jpeg_compress cinfo) { jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef; fdct_controller fdct = null; try { fdct = new fdct_controller(); } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } lossyc.fdct_private = fdct; lossyc.fdct_start_pass = start_pass_fdctmgr; fdct.do_dct = jpeg_fdct_ifast; lossyc.fdct_forward_DCT = forward_DCT; #if DCT_FLOAT_SUPPORTED fdct.do_float_dct = jpeg_fdct_float; if (cinfo.useFloatDCT) { lossyc.fdct_forward_DCT = forward_DCT_float; } #endif // Mark divisor tables unallocated for (int i = 0; i < NUM_QUANT_TBLS; i++) { fdct.divisors[i] = null; #if DCT_FLOAT_SUPPORTED fdct.float_divisors[i] = null; #endif } }
// This version is used for floating-point DCT implementations. static void forward_DCT_float(jpeg_compress cinfo, jpeg_component_info compptr, byte[][] sample_data, short[][] coef_blocks, int coef_offset, uint start_row, uint start_col, uint num_blocks) { // This routine is heavily used, so it's worth coding it tightly jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef; fdct_controller fdct = (fdct_controller)lossyc.fdct_private; float_DCT_method_ptr do_dct = fdct.do_float_dct; double[] divisors = fdct.float_divisors[compptr.quant_tbl_no]; double[] workspace = new double[DCTSIZE2]; // work area for FDCT subroutine for (int bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) { // Load data into workspace, applying unsigned->signed conversion int wsptr = 0; for (int elemr = 0; elemr < DCTSIZE; elemr++) { byte[] elem = sample_data[start_row + elemr]; uint eptr = start_col; // unroll the inner loop workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; } // Perform the DCT do_dct(workspace); // Quantize/descale the coefficients, and store into coef_blocks[] //old short[] output_ptr=coef_blocks[coef_offset][bi]; short[] output_ptr = coef_blocks[coef_offset + bi]; for (int i = 0; i < DCTSIZE2; i++) { // Apply the quantization and scaling factor double temp = workspace[i] * divisors[i]; // Round to nearest integer. // Since C does not specify the direction of rounding for negative // quotients, we have to force the dividend positive for portability. // The maximum coefficient size is +-16K (for 12-bit data), so this // code should work for either 16-bit or 32-bit ints. output_ptr[i] = (short)((int)(temp + 16384.5) - 16384); } } }
// Initialize FDCT manager. static void jinit_forward_dct(jpeg_compress cinfo) { jpeg_lossy_c_codec lossyc=(jpeg_lossy_c_codec)cinfo.coef; fdct_controller fdct=null; try { fdct=new fdct_controller(); } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } lossyc.fdct_private=fdct; lossyc.fdct_start_pass=start_pass_fdctmgr; fdct.do_dct=jpeg_fdct_ifast; lossyc.fdct_forward_DCT=forward_DCT; #if DCT_FLOAT_SUPPORTED fdct.do_float_dct=jpeg_fdct_float; if(cinfo.useFloatDCT) lossyc.fdct_forward_DCT=forward_DCT_float; #endif // Mark divisor tables unallocated for(int i=0; i<NUM_QUANT_TBLS; i++) { fdct.divisors[i]=null; #if DCT_FLOAT_SUPPORTED fdct.float_divisors[i]=null; #endif } }
public static uint jpeg_write_image(jpeg_compress cinfo, byte[] image, bool swapChannels, bool alpha) { if (cinfo.input_components != 3 || cinfo.lossless || cinfo.in_color_space != J_COLOR_SPACE.JCS_RGB || cinfo.num_components != 3 || cinfo.jpeg_color_space != J_COLOR_SPACE.JCS_YCbCr || cinfo.data_precision != 8 || cinfo.DCT_size != 8 || cinfo.block_in_MCU != 3 || cinfo.arith_code || cinfo.max_h_samp_factor != 1 || cinfo.max_v_samp_factor != 1 || cinfo.next_scanline != 0 || cinfo.num_scans != 1) { throw new Exception(); } if (cinfo.global_state != STATE.CSCANNING) { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_BAD_STATE, cinfo.global_state); } // Give master control module another chance if this is first call to // jpeg_write_scanlines. This lets output of the frame/scan headers be // delayed so that application can write COM, etc, markers between // jpeg_start_compress and jpeg_write_scanlines. if (cinfo.master.call_pass_startup) { cinfo.master.pass_startup(cinfo); } jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef; c_coef_controller coef = (c_coef_controller)lossyc.coef_private; fdct_controller fdct = (fdct_controller)lossyc.fdct_private; double[] workspaceY = new double[DCTSIZE2]; double[] workspaceCr = new double[DCTSIZE2]; double[] workspaceCb = new double[DCTSIZE2]; short[][] coefs = new short[][] { new short[DCTSIZE2], new short[DCTSIZE2], new short[DCTSIZE2] }; short[] coefY = coefs[0]; short[] coefCb = coefs[1]; short[] coefCr = coefs[2]; double[] divisorY = fdct.float_divisors[0]; double[] divisorC = fdct.float_divisors[1]; int bpp = alpha?4:3; for (int y = 0; y < (cinfo.image_height + DCTSIZE - 1) / DCTSIZE; y++) { int yFormImage = Math.Min((int)cinfo.image_height - y * DCTSIZE, DCTSIZE); for (int x = 0; x < (cinfo.image_width + DCTSIZE - 1) / DCTSIZE; x++) { int xFormImage = Math.Min((int)cinfo.image_width - x * DCTSIZE, DCTSIZE); int workspacepos = 0; for (int j = 0; j < yFormImage; j++) { int imagepos = ((y * DCTSIZE + j) * (int)cinfo.image_width + x * DCTSIZE) * bpp; for (int i = 0; i < xFormImage; i++, workspacepos++) { byte r = image[imagepos++]; byte g = image[imagepos++]; byte b = image[imagepos++]; if (alpha) { imagepos++; } if (!swapChannels) { workspaceY[workspacepos] = 0.299 * r + 0.587 * g + 0.114 * b - CENTERJSAMPLE; workspaceCb[workspacepos] = -0.168736 * r - 0.331264 * g + 0.5 * b; workspaceCr[workspacepos] = 0.5 * r - 0.418688 * g - 0.081312 * b; } else { workspaceY[workspacepos] = 0.299 * b + 0.587 * g + 0.114 * r - CENTERJSAMPLE; workspaceCb[workspacepos] = -0.168736 * b - 0.331264 * g + 0.5 * r; workspaceCr[workspacepos] = 0.5 * b - 0.418688 * g - 0.081312 * r; } } int lastworkspacepos = workspacepos - 1; for (int i = xFormImage; i < DCTSIZE; i++, workspacepos++) { workspaceY[workspacepos] = workspaceY[lastworkspacepos]; workspaceCb[workspacepos] = workspaceCb[lastworkspacepos]; workspaceCr[workspacepos] = workspaceCr[lastworkspacepos]; } } int lastworkspacelinepos = (yFormImage - 1) * DCTSIZE; for (int j = yFormImage; j < DCTSIZE; j++) { int lastworkspacepos = lastworkspacelinepos; for (int i = 0; i < DCTSIZE; i++, workspacepos++, lastworkspacepos++) { workspaceY[workspacepos] = workspaceY[lastworkspacepos]; workspaceCb[workspacepos] = workspaceCb[lastworkspacepos]; workspaceCr[workspacepos] = workspaceCr[lastworkspacepos]; } } // ein block (3 componenten) jpeg_fdct_float(workspaceY); jpeg_fdct_float(workspaceCb); jpeg_fdct_float(workspaceCr); for (int i = 0; i < DCTSIZE2; i++) { // Apply the quantization and scaling factor double tempY = workspaceY[i] * divisorY[i]; double tempCb = workspaceCb[i] * divisorC[i]; double tempCr = workspaceCr[i] * divisorC[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. coefY[i] = (short)((int)(tempY + 16384.5) - 16384); coefCb[i] = (short)((int)(tempCb + 16384.5) - 16384); coefCr[i] = (short)((int)(tempCr + 16384.5) - 16384); } lossyc.entropy_encode_mcu(cinfo, coefs); } } cinfo.next_scanline = cinfo.image_height; return(cinfo.image_height); }
// 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 } }
// Perform forward DCT on one or more blocks of a component. // // The input samples are taken from the sample_data[] array starting at // position start_row/start_col, and moving to the right for any additional // blocks. The quantized coefficients are returned in coef_blocks[]. // This version is used for integer DCT implementations. static void forward_DCT(jpeg_compress cinfo, jpeg_component_info compptr, byte[][] sample_data, short[][] coef_blocks, int coef_offset, uint start_row, uint start_col, uint num_blocks) { // This routine is heavily used, so it's worth coding it tightly jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef; fdct_controller fdct = (fdct_controller)lossyc.fdct_private; forward_DCT_method_ptr do_dct = fdct.do_dct; int[] divisors = fdct.divisors[compptr.quant_tbl_no]; int[] workspace = new int[DCTSIZE2]; // work area for FDCT subroutine for (int bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) { // Load data into workspace, applying unsigned->signed conversion int wsptr = 0; for (int elemr = 0; elemr < DCTSIZE; elemr++) { byte[] elem = sample_data[start_row + elemr]; uint eptr = start_col; // unroll the inner loop workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; workspace[wsptr++] = elem[eptr++] - CENTERJSAMPLE; } // Perform the DCT do_dct(workspace); // Quantize/descale the coefficients, and store into coef_blocks[] //old short[] output_ptr=coef_blocks[coef_offset][bi]; short[] output_ptr = coef_blocks[coef_offset + bi]; for (int i = 0; i < DCTSIZE2; i++) { int qval = divisors[i]; int temp = workspace[i]; // Divide the coefficient value by qval, ensuring proper rounding. // Since C does not specify the direction of rounding for negative // quotients, we have to force the dividend positive for portability. if (temp < 0) { temp = -temp; temp += qval >> 1; // for rounding temp /= qval; temp = -temp; } else { temp += qval >> 1; // for rounding temp /= qval; } output_ptr[i] = (short)temp; } } }