// Support routine: generate one scan for specified component static int fill_a_scan(jpeg_scan_info[] scanptr, int scanptr_ind, int ci, int Ss, int Se, int Ah, int Al) { jpeg_scan_info scan = scanptr[scanptr_ind]; scan.comps_in_scan = 1; scan.component_index[0] = ci; scan.Ss = Ss; scan.Se = Se; scan.Ah = Ah; scan.Al = Al; scanptr_ind++; return(scanptr_ind); }
// Set up the scan parameters for the current scan static void select_scan_parameters(jpeg_compress cinfo) { #if NEED_SCAN_SCRIPT if (cinfo.scan_info != null) { // Prepare for current scan --- the script is already validated my_comp_master master = (my_comp_master)cinfo.master; jpeg_scan_info scanptr = cinfo.scan_info[master.scan_number]; cinfo.comps_in_scan = scanptr.comps_in_scan; for (int ci = 0; ci < scanptr.comps_in_scan; ci++) { cinfo.cur_comp_info[ci] = cinfo.comp_info[scanptr.component_index[ci]]; } cinfo.Ss = scanptr.Ss; cinfo.Se = scanptr.Se; cinfo.Ah = scanptr.Ah; cinfo.Al = scanptr.Al; } else #endif { // Prepare for single sequential-JPEG scan containing all components if (cinfo.num_components > MAX_COMPS_IN_SCAN) { ERREXIT2(cinfo, J_MESSAGE_CODE.JERR_COMPONENT_COUNT, cinfo.num_components, MAX_COMPS_IN_SCAN); } cinfo.comps_in_scan = cinfo.num_components; for (int ci = 0; ci < cinfo.num_components; ci++) { cinfo.cur_comp_info[ci] = cinfo.comp_info[ci]; } if (cinfo.lossless) { #if C_LOSSLESS_SUPPORTED // If we fall through to here, the user specified lossless, but did not // provide a scan script. ERREXIT(cinfo, J_MESSAGE_CODE.JERR_NO_LOSSLESS_SCRIPT); #endif } else { cinfo.process = J_CODEC_PROCESS.JPROC_SEQUENTIAL; cinfo.Ss = 0; cinfo.Se = DCTSIZE2 - 1; cinfo.Ah = 0; cinfo.Al = 0; } } }
// Support routine: generate one scan for each component static int fill_scans(jpeg_scan_info[] scanptr, int scanptr_ind, int ncomps, int Ss, int Se, int Ah, int Al) { for (int ci = 0; ci < ncomps; ci++) { jpeg_scan_info scan = scanptr[scanptr_ind]; scan.comps_in_scan = 1; scan.component_index[0] = ci; scan.Ss = Ss; scan.Se = Se; scan.Ah = Ah; scan.Al = Al; scanptr_ind++; } return(scanptr_ind); }
// Support routine: generate interleaved DC scan if possible, else N scans static int fill_dc_scans(jpeg_scan_info[] scanptr, int scanptr_ind, int ncomps, int Ah, int Al) { if (ncomps <= MAX_COMPS_IN_SCAN) { jpeg_scan_info scan = scanptr[scanptr_ind]; // Single interleaved DC scan scan.comps_in_scan = ncomps; for (int ci = 0; ci < ncomps; ci++) { scan.component_index[ci] = ci; } scan.Ss = scan.Se = 0; scan.Ah = Ah; scan.Al = Al; scanptr_ind++; } else { // Noninterleaved DC scan for each component scanptr_ind = fill_scans(scanptr, scanptr_ind, ncomps, 0, 0, Ah, Al); } return(scanptr_ind); }
// Support routine: generate interleaved DC scan if possible, else N scans static int fill_dc_scans(jpeg_scan_info[] scanptr, int scanptr_ind, int ncomps, int Ah, int Al) { if(ncomps<=MAX_COMPS_IN_SCAN) { jpeg_scan_info scan=scanptr[scanptr_ind]; // Single interleaved DC scan scan.comps_in_scan=ncomps; for(int ci=0; ci<ncomps; ci++) scan.component_index[ci]=ci; scan.Ss=scan.Se=0; scan.Ah=Ah; scan.Al=Al; scanptr_ind++; } else { // Noninterleaved DC scan for each component scanptr_ind=fill_scans(scanptr, scanptr_ind, ncomps, 0, 0, Ah, Al); } return scanptr_ind; }
// Support routine: generate one scan for specified component static int fill_a_scan(jpeg_scan_info[] scanptr, int scanptr_ind, int ci, int Ss, int Se, int Ah, int Al) { jpeg_scan_info scan=scanptr[scanptr_ind]; scan.comps_in_scan=1; scan.component_index[0]=ci; scan.Ss=Ss; scan.Se=Se; scan.Ah=Ah; scan.Al=Al; scanptr_ind++; return scanptr_ind; }
// Support routine: generate one scan for each component static int fill_scans(jpeg_scan_info[] scanptr, int scanptr_ind, int ncomps, int Ss, int Se, int Ah, int Al) { for(int ci=0; ci<ncomps; ci++) { jpeg_scan_info scan=scanptr[scanptr_ind]; scan.comps_in_scan=1; scan.component_index[0]=ci; scan.Ss=Ss; scan.Se=Se; scan.Ah=Ah; scan.Al=Al; scanptr_ind++; } return scanptr_ind; }
// Create a single-entry lossless-JPEG script containing all components. // cinfo.num_components must be correct. // predictor: 1..7 // point_transform: 0..data_precision(usally 8) // reduction of colors public static void jpeg_simple_lossless(jpeg_compress cinfo, int predictor, int point_transform) { int ncomps = cinfo.num_components; // Safety check to ensure start_compress not called yet. if (cinfo.global_state != STATE.CSTART) { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_BAD_STATE, cinfo.global_state); } cinfo.lossless = true; // Set jpeg_color_space. jpeg_default_colorspace(cinfo); // Check to ensure that all components will fit in one scan. if (cinfo.num_components > MAX_COMPS_IN_SCAN) { ERREXIT2(cinfo, J_MESSAGE_CODE.JERR_COMPONENT_COUNT, cinfo.num_components, MAX_COMPS_IN_SCAN); } // Allocate space for script. // We need to put it in the permanent pool in case the application performs // multiple compressions without changing the settings. To avoid a memory // leak if jpeg_simple_lossless is called repeatedly for the same JPEG // object, we try to re-use previously allocated space. int nscans = 1; if (cinfo.script_space == null || cinfo.script_space_size < nscans) { cinfo.script_space_size = nscans; try { cinfo.script_space = new jpeg_scan_info[cinfo.script_space_size]; for (int i = 0; i < cinfo.script_space_size; i++) { cinfo.script_space[i] = new jpeg_scan_info(); } } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } } jpeg_scan_info scanptr = cinfo.script_space[0]; cinfo.scan_info = cinfo.script_space; cinfo.num_scans = nscans; // Fill the script. scanptr.comps_in_scan = ncomps; for (int ci = 0; ci < ncomps; ci++) { scanptr.component_index[ci] = ci; } scanptr.Ss = predictor; scanptr.Se = 0; scanptr.Ah = 0; scanptr.Al = point_transform; }
// Verify that the scan script in cinfo.scan_info[] is valid; also // determine whether it uses progressive JPEG, and set cinfo.process. static void validate_script(jpeg_compress cinfo) { #if C_PROGRESSIVE_SUPPORTED int[,] last_bitpos = new int[MAX_COMPONENTS, DCTSIZE2]; // -1 until that coefficient has been seen; then last Al for it #endif if (cinfo.num_scans <= 0) { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_BAD_SCAN_SCRIPT, 0); } #if !C_MULTISCAN_FILES_SUPPORTED if (cinfo.num_scans > 1) { ERREXIT(cinfo, J_MESSAGE_CODE.JERR_NOT_COMPILED); } #endif bool[] component_sent = new bool[MAX_COMPONENTS]; if (cinfo.lossless) { #if C_LOSSLESS_SUPPORTED cinfo.process = J_CODEC_PROCESS.JPROC_LOSSLESS; for (int ci = 0; ci < cinfo.num_components; ci++) { component_sent[ci] = false; } #else ERREXIT(cinfo, J_MESSAGE_CODE.JERR_NOT_COMPILED); #endif } // For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1; // for progressive JPEG, no scan can have this. else if (cinfo.scan_info[0].Ss != 0 || cinfo.scan_info[0].Se != DCTSIZE2 - 1) { #if C_PROGRESSIVE_SUPPORTED cinfo.process = J_CODEC_PROCESS.JPROC_PROGRESSIVE; for (int ci = 0; ci < cinfo.num_components; ci++) { for (int coefi = 0; coefi < DCTSIZE2; coefi++) { last_bitpos[ci, coefi] = -1; } } #else ERREXIT(cinfo, J_MESSAGE_CODE.JERR_NOT_COMPILED); #endif } else { cinfo.process = J_CODEC_PROCESS.JPROC_SEQUENTIAL; for (int ci = 0; ci < cinfo.num_components; ci++) { component_sent[ci] = false; } } for (int scanno = 1; scanno <= cinfo.num_scans; scanno++) { jpeg_scan_info scan_info = cinfo.scan_info[scanno - 1]; // Validate component indexes int ncomps = scan_info.comps_in_scan; if (ncomps <= 0 || ncomps > MAX_COMPS_IN_SCAN) { ERREXIT2(cinfo, J_MESSAGE_CODE.JERR_COMPONENT_COUNT, ncomps, MAX_COMPS_IN_SCAN); } for (int ci = 0; ci < ncomps; ci++) { int thisi = scan_info.component_index[ci]; if (thisi < 0 || thisi >= cinfo.num_components) { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_BAD_SCAN_SCRIPT, scanno); } // Components must appear in SOF order within each scan if (ci > 0 && thisi <= scan_info.component_index[ci - 1]) { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_BAD_SCAN_SCRIPT, scanno); } } // Validate progression parameters int Ss = scan_info.Ss; int Se = scan_info.Se; int Ah = scan_info.Ah; int Al = scan_info.Al; if (cinfo.process == J_CODEC_PROCESS.JPROC_LOSSLESS) { #if C_LOSSLESS_SUPPORTED // The JPEG spec simply gives the range 0..15 for Al (Pt), but that // seems wrong: the upper bound ought to depend on data precision. // Perhaps they really meant 0..N-1 for N-bit precision, which is what // we allow here. if (Ss < 1 || Ss > 7 || Se != 0 || Ah != 0 || Al < 0 || Al >= cinfo.data_precision) // Ss predictor selector; Al point transform { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_BAD_LOSSLESS_SCRIPT, scanno); } // Make sure components are not sent twice for (int ci = 0; ci < ncomps; ci++) { int thisi = scan_info.component_index[ci]; if (component_sent[thisi]) { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_BAD_SCAN_SCRIPT, scanno); } component_sent[thisi] = true; } #endif } else if (cinfo.process == J_CODEC_PROCESS.JPROC_PROGRESSIVE) { #if C_PROGRESSIVE_SUPPORTED // The JPEG spec simply gives the ranges 0..13 for Ah and Al, but that // seems wrong: the upper bound ought to depend on data precision. // Perhaps they really meant 0..N+1 for N-bit precision. // Here we allow 0..10 for 8-bit data; Al larger than 10 results in // out-of-range reconstructed DC values during the first DC scan, // which might cause problems for some decoders. const int MAX_AH_AL = 10; if (Ss < 0 || Ss >= DCTSIZE2 || Se < Ss || Se >= DCTSIZE2 || Ah < 0 || Ah > MAX_AH_AL || Al < 0 || Al > MAX_AH_AL) { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_BAD_PROG_SCRIPT, scanno); } if (Ss == 0) { if (Se != 0) { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_BAD_PROG_SCRIPT, scanno); // DC and AC together not OK } } else { if (ncomps != 1) { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_BAD_PROG_SCRIPT, scanno); // AC scans must be for only one component } } for (int ci = 0; ci < ncomps; ci++) { int comp_ind = scan_info.component_index[ci]; if (Ss != 0 && last_bitpos[comp_ind, 0] < 0) { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_BAD_PROG_SCRIPT, scanno); // AC without prior DC scan } for (int coefi = Ss; coefi <= Se; coefi++) { if (last_bitpos[comp_ind, coefi] < 0) { // first scan of this coefficient if (Ah != 0) { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_BAD_PROG_SCRIPT, scanno); } } else { // not first scan if (Ah != last_bitpos[comp_ind, coefi] || Al != Ah - 1) { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_BAD_PROG_SCRIPT, scanno); } } last_bitpos[comp_ind, coefi] = Al; } } #endif // C_PROGRESSIVE_SUPPORTED } else { // For sequential JPEG, all progression parameters must be these: if (Ss != 0 || Se != DCTSIZE2 - 1 || Ah != 0 || Al != 0) { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_BAD_PROG_SCRIPT, scanno); } // Make sure components are not sent twice for (int ci = 0; ci < ncomps; ci++) { int thisi = scan_info.component_index[ci]; if (component_sent[thisi]) { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_BAD_SCAN_SCRIPT, scanno); } component_sent[thisi] = true; } } } // for(...) // Now verify that everything got sent. if (cinfo.process == J_CODEC_PROCESS.JPROC_PROGRESSIVE) { #if C_PROGRESSIVE_SUPPORTED // For progressive mode, we only check that at least some DC data // got sent for each component; the spec does not require that all bits // of all coefficients be transmitted. Would it be wiser to enforce // transmission of all coefficient bits?? for (int ci = 0; ci < cinfo.num_components; ci++) { if (last_bitpos[ci, 0] < 0) { ERREXIT(cinfo, J_MESSAGE_CODE.JERR_MISSING_DATA); } } #endif } else { for (int ci = 0; ci < cinfo.num_components; ci++) { if (!component_sent[ci]) { ERREXIT(cinfo, J_MESSAGE_CODE.JERR_MISSING_DATA); } } } }