JPEG compression routine.
Inheritance: jpeg_common_struct
Exemplo n.º 1
0
        private static void compress(Stream input, CompressOptions options, Stream output)
        {
            Debug.Assert(input != null);
            Debug.Assert(options != null);
            Debug.Assert(output != null);

            jpeg_compress_struct cinfo = new jpeg_compress_struct(new cd_jpeg_error_mgr());

            /* Initialize JPEG parameters.
             * Much of this may be overridden later.
             * In particular, we don't yet know the input file's color space,
             * but we need to provide some value for jpeg_set_defaults() to work.
             */
            cinfo.In_color_space = J_COLOR_SPACE.JCS_RGB; /* arbitrary guess */
            cinfo.jpeg_set_defaults();

            /* Figure out the input file format, and set up to read it. */
            cjpeg_source_struct src_mgr = new bmp_source_struct(cinfo);
            src_mgr.input_file = input;

            /* Read the input file header to obtain file size & colorspace. */
            src_mgr.start_input();

            /* Now that we know input colorspace, fix colorspace-dependent defaults */
            cinfo.jpeg_default_colorspace();

            /* Adjust default compression parameters */
            if (!applyOptions(cinfo, options))
                return;

            /* Specify data destination for compression */
            cinfo.jpeg_stdio_dest(output);

            /* Start compressor */
            cinfo.jpeg_start_compress(true);

            /* Process data */
            while (cinfo.Next_scanline < cinfo.Image_height)
            {
                int num_scanlines = src_mgr.get_pixel_rows();
                cinfo.jpeg_write_scanlines(src_mgr.buffer, num_scanlines);
            }

            /* Finish compression and release memory */
            src_mgr.finish_input();
            cinfo.jpeg_finish_compress();

            /* All done. */
            if (cinfo.Err.Num_warnings != 0)
                Console.WriteLine("Corrupt-data warning count is not zero");
        }
Exemplo n.º 2
0
        public void TestCompressorWithContextRows()
        {
            using (MemoryStream stream = new MemoryStream())
            {
                jpeg_compress_struct compressor = new jpeg_compress_struct(new jpeg_error_mgr());
                compressor.Image_height = 100;
                compressor.Image_width = 100;
                compressor.In_color_space = J_COLOR_SPACE.JCS_GRAYSCALE;
                compressor.Input_components = 1;
                compressor.jpeg_set_defaults();

                compressor.Dct_method = J_DCT_METHOD.JDCT_IFAST;
                compressor.Smoothing_factor = 94;
                compressor.jpeg_set_quality(75, true);
                compressor.jpeg_simple_progression();

                compressor.Density_unit = DensityUnit.Unknown;
                compressor.X_density = (short)96;
                compressor.Y_density = (short)96;

                compressor.jpeg_stdio_dest(stream);
                compressor.jpeg_start_compress(true);

                byte[][] rowForDecompressor = new byte[1][];
                int bytesPerPixel = 1;
                while (compressor.Next_scanline < compressor.Image_height)
                {
                    byte[] row = new byte[100 * bytesPerPixel]; // wasteful, but gets you 0 bytes every time - content is immaterial.
                    rowForDecompressor[0] = row;
                    compressor.jpeg_write_scanlines(rowForDecompressor, 1);
                }
                compressor.jpeg_finish_compress();

                byte[] bytes = stream.ToArray();

                string filename = "TestCompressorWithContextRows.jpg";
                File.WriteAllBytes(Tester.MapOutputPath(filename), bytes);
                FileAssert.AreEqual(Tester.MapExpectedPath(filename), Tester.MapOutputPath(filename));
            }
        }
Exemplo n.º 3
0
 static bool set_sample_factors(jpeg_compress_struct cinfo, string arg)
 {
     // not implemented yet
     return false;
 }
Exemplo n.º 4
0
 static bool set_quant_slots(jpeg_compress_struct cinfo, string arg)
 {
     // not implemented yet
     return false;
 }
Exemplo n.º 5
0
 static bool read_quant_tables(jpeg_compress_struct cinfo, string filename, int scale_factor, bool force_baseline)
 {
     // not implemented yet
     return false;
 }
Exemplo n.º 6
0
        private static bool applyOptions(jpeg_compress_struct compressor, CompressOptions options)
        {
            compressor.jpeg_set_quality(options.Quality, options.ForceBaseline);
            compressor.Dct_method = options.DCTMethod;

            if (options.Debug)
                compressor.Err.Trace_level = 1;

            if (options.Grayscale)
                compressor.jpeg_set_colorspace(J_COLOR_SPACE.JCS_GRAYSCALE);

            if (options.Optimize)
                compressor.Optimize_coding = true;

            compressor.Restart_interval = options.RestartInterval;
            compressor.Restart_in_rows = options.RestartInRows;

            compressor.Smoothing_factor = options.SmoothingFactor;

            int q_scale_factor = 100;
            if (options.Quality != 75)
                q_scale_factor = jpeg_compress_struct.jpeg_quality_scaling(options.Quality);

            /* Set quantization tables for selected quality. */
            /* Some or all may be overridden if -qtables is present. */
            if (options.Qtables != "") /* process -qtables if it was present */
            {
                if (!read_quant_tables(compressor, options.Qtables, q_scale_factor, options.ForceBaseline))
                    return false;
            }

            if (options.Qslots != "")  /* process -qslots if it was present */
            {
                if (!set_quant_slots(compressor, options.Qslots))
                    return false;
            }

            if (options.Sample != "")  /* process -sample if it was present */
            {
                if (!set_sample_factors(compressor, options.Sample))
                    return false;
            }

            if (options.Progressive) /* process -progressive; -scans can override */
                compressor.jpeg_simple_progression();

            return true;
        }
        /// <summary>
        /// Initializes the compression object with default parameters, then copy from the source object 
        /// all parameters needed for lossless transcoding.
        /// </summary>
        /// <param name="dstinfo">Target JPEG compression object.</param>
        /// <remarks>Parameters that can be varied without loss (such as scan script and 
        /// Huffman optimization) are left in their default states.</remarks>
        public void jpeg_copy_critical_parameters(jpeg_compress_struct dstinfo)
        {
            /* Safety check to ensure start_compress not called yet. */
            if (dstinfo.m_global_state != JpegState.CSTATE_START)
                ERREXIT(J_MESSAGE_CODE.JERR_BAD_STATE, (int)dstinfo.m_global_state);

            /* Copy fundamental image dimensions */
            dstinfo.m_image_width = m_image_width;
            dstinfo.m_image_height = m_image_height;
            dstinfo.m_input_components = m_num_components;
            dstinfo.m_in_color_space = m_jpeg_color_space;

            /* Initialize all parameters to default values */
            dstinfo.jpeg_set_defaults();

            /* jpeg_set_defaults may choose wrong colorspace, eg YCbCr if input is RGB.
            * Fix it to get the right header markers for the image colorspace.
            */
            dstinfo.jpeg_set_colorspace(m_jpeg_color_space);
            dstinfo.m_data_precision = m_data_precision;
            dstinfo.m_CCIR601_sampling = m_CCIR601_sampling;

            /* Copy the source's quantization tables. */
            for (int tblno = 0; tblno < JpegConstants.NUM_QUANT_TBLS; tblno++)
            {
                if (m_quant_tbl_ptrs[tblno] != null)
                {
                    if (dstinfo.m_quant_tbl_ptrs[tblno] == null)
                        dstinfo.m_quant_tbl_ptrs[tblno] = new JQUANT_TBL();

                    Buffer.BlockCopy(m_quant_tbl_ptrs[tblno].quantval, 0,
                        dstinfo.m_quant_tbl_ptrs[tblno].quantval, 0,
                        dstinfo.m_quant_tbl_ptrs[tblno].quantval.Length * sizeof(short));

                    dstinfo.m_quant_tbl_ptrs[tblno].Sent_table = false;
                }
            }

            /* Copy the source's per-component info.
            * Note we assume jpeg_set_defaults has allocated the dest comp_info array.
            */
            dstinfo.m_num_components = m_num_components;
            if (dstinfo.m_num_components < 1 || dstinfo.m_num_components> JpegConstants.MAX_COMPONENTS)
                ERREXIT(J_MESSAGE_CODE.JERR_COMPONENT_COUNT, dstinfo.m_num_components, JpegConstants.MAX_COMPONENTS);

            for (int ci = 0; ci < dstinfo.m_num_components; ci++)
            {
                dstinfo.Component_info[ci].Component_id = m_comp_info[ci].Component_id;
                dstinfo.Component_info[ci].H_samp_factor = m_comp_info[ci].H_samp_factor;
                dstinfo.Component_info[ci].V_samp_factor = m_comp_info[ci].V_samp_factor;
                dstinfo.Component_info[ci].Quant_tbl_no = m_comp_info[ci].Quant_tbl_no;

                /* Make sure saved quantization table for component matches the qtable
                * slot.  If not, the input file re-used this qtable slot.
                * IJG encoder currently cannot duplicate this.
                */
                int tblno = dstinfo.Component_info[ci].Quant_tbl_no;
                if (tblno < 0 || tblno >= JpegConstants.NUM_QUANT_TBLS || m_quant_tbl_ptrs[tblno] == null)
                    ERREXIT(J_MESSAGE_CODE.JERR_NO_QUANT_TABLE, tblno);

                JQUANT_TBL c_quant = m_comp_info[ci].quant_table;
                if (c_quant != null)
                {
                    JQUANT_TBL slot_quant = m_quant_tbl_ptrs[tblno];
                    for (int coefi = 0; coefi < JpegConstants.DCTSIZE2; coefi++)
                    {
                        if (c_quant.quantval[coefi] != slot_quant.quantval[coefi])
                            ERREXIT(J_MESSAGE_CODE.JERR_MISMATCHED_QUANT_TABLE, tblno);
                    }
                }
                /* Note: we do not copy the source's Huffman table assignments;
                * instead we rely on jpeg_set_colorspace to have made a suitable choice.
                */
            }

            /* Also copy JFIF version and resolution information, if available.
            * Strictly speaking this isn't "critical" info, but it's nearly
            * always appropriate to copy it if available.  In particular,
            * if the application chooses to copy JFIF 1.02 extension markers from
            * the source file, we need to copy the version to make sure we don't
            * emit a file that has 1.02 extensions but a claimed version of 1.01.
            * We will *not*, however, copy version info from mislabeled "2.01" files.
            */
            if (m_saw_JFIF_marker)
            {
                if (m_JFIF_major_version == 1)
                {
                    dstinfo.m_JFIF_major_version = m_JFIF_major_version;
                    dstinfo.m_JFIF_minor_version = m_JFIF_minor_version;
                }

                dstinfo.m_density_unit = m_density_unit;
                dstinfo.m_X_density = (short)m_X_density;
                dstinfo.m_Y_density = (short)m_Y_density;
            }
        }
Exemplo n.º 8
0
        private void cleanState()
        {
            m_compression = null;
            m_decompression = null;
            m_common = null;

            m_h_sampling = 0;
            m_v_sampling = 0;

            m_jpegtables = null;
            m_jpegtables_length = 0;
            m_jpegquality = 0;
            m_jpegcolormode = 0;
            m_jpegtablesmode = 0;

            m_ycbcrsampling_fetched = false;

            m_recvparams = 0;
            m_subaddress = null;
            m_recvtime = 0;
            m_faxdcs = null;
            m_rawDecode = false;
            m_rawEncode = false;

            m_cinfo_initialized = false;

            m_err = null;
            m_photometric = 0;

            m_bytesperline = 0;
            m_ds_buffer = new byte[JpegConstants.MAX_COMPONENTS][][];
            m_scancount = 0;
            m_samplesperclump = 0;
        }
Exemplo n.º 9
0
        /*
        * Interface routines.  This layer of routines exists
        * primarily to limit side-effects from LibJpeg.Net exceptions.
        * Also, normal/error returns are converted into return
        * values per LibTiff.Net practice.
        */
        private bool TIFFjpeg_create_compress()
        {
            /* initialize JPEG error handling */
            try
            {
                m_compression = new jpeg_compress_struct(new JpegErrorManager(this));
                m_common = m_compression;
            }
            catch (Exception)
            {
                return false;
            }

            return true;
        }
Exemplo n.º 10
0
 public bmp_source_struct(jpeg_compress_struct cinfo)
 {
     this.cinfo = cinfo;
 }
Exemplo n.º 11
0
 public static string IncImageDCT(string fullPath)
 {
     string suffix = "testDCT";
     var img = new Bitmap(fullPath);
     var width = img.Width;
     var height = img.Height;
     int hd = height / 8;
     int wd = width / 8;
     img.Dispose();
     BitMiracle.LibJpeg.Classic.jpeg_decompress_struct oJpegDecompress = new BitMiracle.LibJpeg.Classic.jpeg_decompress_struct();
     System.IO.FileStream oFileStreamImage = new System.IO.FileStream(fullPath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
     oJpegDecompress.jpeg_stdio_src(oFileStreamImage);
     oJpegDecompress.jpeg_read_header(true);
     BitMiracle.LibJpeg.Classic.jvirt_array<BitMiracle.LibJpeg.Classic.JBLOCK>[] JBlock = oJpegDecompress.jpeg_read_coefficients();
     var block = JBlock[0].Access(0, hd); // accessing the element
     for (int i = 0; i < hd; i++)
     {
         for (int j = 0; j < wd; j++)
         {
             short t = block[i][j].data[0];
             if ((t >= 0 && t % 2 == 1) || (t < 0 && t % 2 == 0))
             {
                 t--;
             }
             else if ((t >= 0 && t % 2 == 0) || (t < 0 && t % 2 == 1))
             {
                 t++;
             }
             block[i][j].data[0] = t;
         }
     }
     oJpegDecompress.jpeg_finish_decompress();
     oFileStreamImage.Close();
     ////
     string filenameNew = MyHelper.AppendFileName(fullPath, suffix);
     System.IO.FileStream objFileStreamMegaMap = System.IO.File.Create(filenameNew);
     BitMiracle.LibJpeg.Classic.jpeg_compress_struct oJpegCompress = new BitMiracle.LibJpeg.Classic.jpeg_compress_struct();
     oJpegCompress.jpeg_stdio_dest(objFileStreamMegaMap);
     oJpegDecompress.jpeg_copy_critical_parameters(oJpegCompress);
     oJpegCompress.Image_height = height;
     oJpegCompress.Image_width = width;
     oJpegCompress.jpeg_write_coefficients(JBlock);
     oJpegCompress.jpeg_finish_compress();
     objFileStreamMegaMap.Close();
     oJpegDecompress.jpeg_abort_decompress();
     return filenameNew;
 }
Exemplo n.º 12
0
        static string outfilename;   /* for -outfile switch */

        public static void Main(string[] args)
        {
            progname = Path.GetFileName(Environment.GetCommandLineArgs()[0]);

            cd_jpeg_error_mgr err = new cd_jpeg_error_mgr();
            jpeg_compress_struct cinfo = new jpeg_compress_struct(err);

            /* Initialize JPEG parameters.
             * Much of this may be overridden later.
             * In particular, we don't yet know the input file's color space,
             * but we need to provide some value for jpeg_set_defaults() to work.
             */

            cinfo.In_color_space = J_COLOR_SPACE.JCS_RGB; /* arbitrary guess */
            cinfo.jpeg_set_defaults();

            /* Scan command line to find file names.
             * It is convenient to use just one switch-parsing routine, but the switch
             * values read here are ignored; we will rescan the switches after opening
             * the input file.
             */
            int file_index;
            if (!parse_switches(cinfo, args, false, out file_index))
            {
                usage();
                return;
            }

            /* Must have either -outfile switch or explicit output file name */
            if (outfilename == null)
            {
                // file_index should point to input file 
                if (file_index != args.Length - 2)
                {
                    Console.WriteLine(string.Format("{0}: must name one input and one output file.", progname));
                    usage();
                    return;
                }

                // output file comes right after input one
                outfilename = args[file_index + 1];
            }
            else
            {
                // file_index should point to input file
                if (file_index != args.Length - 1)
                {
                    Console.WriteLine(string.Format("{0}: must name one input and one output file.", progname));
                    usage();
                    return;
                }
            }

            /* Open the input file. */
            FileStream input_file = null;
            if (file_index < args.Length)
            {
                try
                {
                    input_file = new FileStream(args[file_index], FileMode.Open);
                }
                catch (Exception e)
                {
                    Console.WriteLine(string.Format("{0}: can't open {1}", progname, args[file_index]));
                    Console.WriteLine(e.Message);
                    return;
                }
            }
            else
            {
                Console.WriteLine(string.Format("{0}: sorry, can't read file from console"));
                return;
            }

            /* Open the output file. */
            FileStream output_file = null;
            if (outfilename != null)
            {
                try
                {
                    output_file = new FileStream(outfilename, FileMode.Create);
                }
                catch (Exception e)
                {
                    Console.WriteLine(string.Format("{0}: can't open {1}", progname, args[file_index]));
                    Console.WriteLine(e.Message);
                    return;	
                }
            }
            else
            {
                Console.WriteLine(string.Format("{0}: sorry, can't write file to console"));
                return;
            }

            /* Figure out the input file format, and set up to read it. */
            cjpeg_source_struct src_mgr = new bmp_source_struct(cinfo);
            src_mgr.input_file = input_file;

            /* Read the input file header to obtain file size & colorspace. */
            src_mgr.start_input();

            /* Now that we know input colorspace, fix colorspace-dependent defaults */
            cinfo.jpeg_default_colorspace();

            /* Adjust default compression parameters by re-parsing the options */
            parse_switches(cinfo, args, true, out file_index);

            /* Specify data destination for compression */
            cinfo.jpeg_stdio_dest(output_file);

            /* Start compressor */
            cinfo.jpeg_start_compress(true);

            /* Process data */
            while (cinfo.Next_scanline < cinfo.Image_height)
            {
                int num_scanlines = src_mgr.get_pixel_rows();
                cinfo.jpeg_write_scanlines(src_mgr.buffer, num_scanlines);
            }

            /* Finish compression and release memory */
            src_mgr.finish_input();
            cinfo.jpeg_finish_compress();

            /* Close files, if we opened them */
            input_file.Close();
            input_file.Dispose();

            output_file.Close();
            output_file.Dispose();

            /* All done. */
            if (cinfo.Err.Num_warnings != 0)
                Console.WriteLine("Corrupt-data warning count is not zero");
        }
Exemplo n.º 13
0
        /// <summary>
        /// Parse optional switches.
        /// Returns true if switches were parsed successfully; false otherwise.
        /// fileIndex receives index of first file-name argument (== -1 if none).
        /// for_real is false on the first (dummy) pass; we may skip any expensive
        /// processing.
        /// </summary>
        static bool parse_switches(jpeg_compress_struct cinfo, string[] argv, bool for_real, out int fileIndex)
        {
            /* Set up default JPEG parameters. */
            /* Note that default -quality level need not, and does not,
             * match the default scaling for an explicit -qtables argument.
             */
            int quality = 75;           /* default -quality value */
            int q_scale_factor = 100;       /* default to no scaling for -qtables */
            bool force_baseline = false; /* by default, allow 16-bit quantizers */
            bool simple_progressive = false;

            string qtablefile = null;    /* saves -qtables filename if any */
            string qslotsarg = null; /* saves -qslots parm if any */
            string samplearg = null; /* saves -sample parm if any */

            outfilename = null;
            fileIndex = -1;
            cinfo.Err.Trace_level = 0;

            /* Scan command line options, adjust parameters */
            int argn = 0;
            for ( ; argn < argv.Length; argn++)
            {
                string arg = argv[argn];
                if (string.IsNullOrEmpty(arg) || arg[0] != '-')
                {
                    /* Not a switch, must be a file name argument */
                    fileIndex = argn;
                    break;
                }

                arg = arg.Substring(1);

                if (cdjpeg_utils.keymatch(arg, "baseline", 1))
                {
                    /* Force baseline-compatible output (8-bit quantizer values). */
                    force_baseline = true;
                }
                else if (cdjpeg_utils.keymatch(arg, "dct", 2))
                {
                    /* Select DCT algorithm. */
                    argn++; /* advance to next argument */
                    if (argn >= argv.Length)
                        return false;

                    if (cdjpeg_utils.keymatch(argv[argn], "int", 1))
                        cinfo.Dct_method = J_DCT_METHOD.JDCT_ISLOW;
                    else if (cdjpeg_utils.keymatch(argv[argn], "fast", 2))
                        cinfo.Dct_method = J_DCT_METHOD.JDCT_IFAST;
                    else if (cdjpeg_utils.keymatch(argv[argn], "float", 2))
                        cinfo.Dct_method = J_DCT_METHOD.JDCT_FLOAT;
                    else
                        return false;
                }
                else if (cdjpeg_utils.keymatch(arg, "debug", 1) || cdjpeg_utils.keymatch(arg, "verbose", 1))
                {
                    /* Enable debug printouts. */
                    /* On first -d, print version identification */
                    if (!printed_version)
                    {
                        Console.Write(string.Format("Bit Miracle's CJPEG, version {0}\n{1}\n", jpeg_common_struct.Version, jpeg_common_struct.Copyright));
                        printed_version = true;
                    }
                    cinfo.Err.Trace_level++;
                }
                else if (cdjpeg_utils.keymatch(arg, "grayscale", 2) || cdjpeg_utils.keymatch(arg, "greyscale", 2))
                {
                    /* Force a monochrome JPEG file to be generated. */
                    cinfo.jpeg_set_colorspace(J_COLOR_SPACE.JCS_GRAYSCALE);
                }
                else if (cdjpeg_utils.keymatch(arg, "optimize", 1) || cdjpeg_utils.keymatch(arg, "optimise", 1))
                {
                    /* Enable entropy parm optimization. */
                    cinfo.Optimize_coding = true;
                }
                else if (cdjpeg_utils.keymatch(arg, "outfile", 4))
                {
                    /* Set output file name. */
                    argn++;/* advance to next argument */
                    if (argn >= argv.Length)
                        return false;

                    outfilename = argv[argn];   /* save it away for later use */
                }
                else if (cdjpeg_utils.keymatch(arg, "progressive", 1))
                {
                    /* Select simple progressive mode. */
                    simple_progressive = true;
                    /* We must postpone execution until num_components is known. */
                }
                else if (cdjpeg_utils.keymatch(arg, "quality", 1))
                {
                    /* Quality factor (quantization table scaling factor). */
                    argn++;/* advance to next argument */
                    if (argn >= argv.Length)
                        return false;

                    try
                    {
                        quality = int.Parse(argv[argn]);
                        /* Change scale factor in case -qtables is present. */
                        q_scale_factor = jpeg_compress_struct.jpeg_quality_scaling(quality);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.Message);
                        return false;
                    }
                }
                else if (cdjpeg_utils.keymatch(arg, "qslots", 2))
                {
                    /* Quantization table slot numbers. */
                    argn++; /* advance to next argument */
                    if (argn >= argv.Length)
                        return false;

                    qslotsarg = argv[argn];
                    /* Must delay setting qslots until after we have processed any
                     * colorspace-determining switches, since jpeg_set_colorspace sets
                     * default quant table numbers.
                     */
                }
                else if (cdjpeg_utils.keymatch(arg, "qtables", 2))
                {
                    /* Quantization tables fetched from file. */
                    argn++; /* advance to next argument */
                    if (argn >= argv.Length)
                        return false;

                    qtablefile = argv[argn];
                    /* We postpone actually reading the file in case -quality comes later. */
                }
                else if (cdjpeg_utils.keymatch(arg, "restart", 1))
                {
                    /* Restart interval in MCU rows (or in MCUs with 'b'). */
                    argn++; /* advance to next argument */

                    if (argn >= argv.Length)
                        return false;

                    bool inBlocks = false;
                    if (argv[argn].EndsWith("b") || argv[argn].EndsWith("B"))
                        inBlocks = true;

                    string parsee = argv[argn];
                    if (inBlocks)
                        parsee = parsee.Remove(parsee.Length - 1);

                    try
                    {
                        int val = int.Parse(parsee);
                        if (val < 0 || val > 65535)
                            return false;

                        if (inBlocks)
                        {
                            cinfo.Restart_interval = val;
                            cinfo.Restart_in_rows = 0; /* else prior '-restart n' overrides me */
                        }
                        else
                        {
                            cinfo.Restart_in_rows = val;
                            /* restart_interval will be computed during startup */
                        }
                    }
                    catch (Exception e)
                    {
                    	Console.WriteLine(e.Message);
                        return false;
                    }
                }
                else if (cdjpeg_utils.keymatch(arg, "sample", 2))
                {
                    /* Set sampling factors. */
                    argn++; /* advance to next argument */
                    if (argn >= argv.Length)
                        return false;

                    samplearg = argv[argn];
                    /* Must delay setting sample factors until after we have processed any
                     * colorspace-determining switches, since jpeg_set_colorspace sets
                     * default sampling factors.
                     */
                }
                else if (cdjpeg_utils.keymatch(arg, "smooth", 2))
                {
                    /* Set input smoothing factor. */

                    argn++; /* advance to next argument */
                    if (argn >= argv.Length)
                        return false;

                    try
                    {
                        int val = int.Parse(argv[argn]);
                        if (val < 0 || val > 100)
                            return false;

                        cinfo.Smoothing_factor = val;
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.Message);
                        return false;
                    }
                }
                else
                {
                    /* bogus switch */
                    return false;
                }
            }

            /* Post-switch-scanning cleanup */

            if (for_real)
            {
                /* Set quantization tables for selected quality. */
                /* Some or all may be overridden if -qtables is present. */
                cinfo.jpeg_set_quality(quality, force_baseline);

                if (qtablefile != null) /* process -qtables if it was present */
                {
                    if (!read_quant_tables(cinfo, qtablefile, q_scale_factor, force_baseline))
                        return false;
                }

                if (qslotsarg != null)  /* process -qslots if it was present */
                {
                    if (!set_quant_slots(cinfo, qslotsarg))
                        return false;
                }

                if (samplearg != null)  /* process -sample if it was present */
                {
                    if (!set_sample_factors(cinfo, samplearg))
                        return false;
                }

                if (simple_progressive) /* process -progressive; -scans can override */
                    cinfo.jpeg_simple_progression();
            }

            return true;
        }