home *** CD-ROM | disk | FTP | other *** search
/ Encyclopedia of Graphics File Formats Companion / GFF_CD.ISO / software / unix / jpeg / jpegv4a.tar / jcmain.c < prev    next >
C/C++ Source or Header  |  1993-02-16  |  22KB  |  734 lines

  1. /*
  2.  * jcmain.c
  3.  *
  4.  * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  5.  * This file is part of the Independent JPEG Group's software.
  6.  * For conditions of distribution and use, see the accompanying README file.
  7.  *
  8.  * This file contains a command-line user interface for the JPEG compressor.
  9.  * It should work on any system with Unix- or MS-DOS-style command lines.
  10.  *
  11.  * Two different command line styles are permitted, depending on the
  12.  * compile-time switch TWO_FILE_COMMANDLINE:
  13.  *    cjpeg [options]  inputfile outputfile
  14.  *    cjpeg [options]  [inputfile]
  15.  * In the second style, output is always to standard output, which you'd
  16.  * normally redirect to a file or pipe to some other program.  Input is
  17.  * either from a named file or from standard input (typically redirected).
  18.  * The second style is convenient on Unix but is unhelpful on systems that
  19.  * don't support pipes.  Also, you MUST use the first style if your system
  20.  * doesn't do binary I/O to stdin/stdout.
  21.  * To simplify script writing, the "-outfile" switch is provided.  The syntax
  22.  *    cjpeg [options]  -outfile outputfile  inputfile
  23.  * works regardless of which command line style is used.
  24.  */
  25.  
  26. #include "jinclude.h"
  27. #ifdef INCLUDES_ARE_ANSI
  28. #include <stdlib.h>        /* to declare exit() */
  29. #endif
  30. #include <ctype.h>        /* to declare isupper(), tolower() */
  31. #ifdef NEED_SIGNAL_CATCHER
  32. #include <signal.h>        /* to declare signal() */
  33. #endif
  34. #ifdef USE_SETMODE
  35. #include <fcntl.h>        /* to declare setmode() */
  36. #endif
  37.  
  38. #ifdef THINK_C
  39. #include <console.h>        /* command-line reader for Macintosh */
  40. #endif
  41.  
  42. #ifdef DONT_USE_B_MODE        /* define mode parameters for fopen() */
  43. #define READ_BINARY    "r"
  44. #define WRITE_BINARY    "w"
  45. #else
  46. #define READ_BINARY    "rb"
  47. #define WRITE_BINARY    "wb"
  48. #endif
  49.  
  50. #ifndef EXIT_FAILURE        /* define exit() codes if not provided */
  51. #define EXIT_FAILURE  1
  52. #endif
  53. #ifndef EXIT_SUCCESS
  54. #ifdef VMS
  55. #define EXIT_SUCCESS  1        /* VMS is very nonstandard */
  56. #else
  57. #define EXIT_SUCCESS  0
  58. #endif
  59. #endif
  60.  
  61.  
  62. #include "jversion.h"        /* for version message */
  63.  
  64.  
  65. /*
  66.  * This routine determines what format the input file is,
  67.  * and selects the appropriate input-reading module.
  68.  *
  69.  * To determine which family of input formats the file belongs to,
  70.  * we may look only at the first byte of the file, since C does not
  71.  * guarantee that more than one character can be pushed back with ungetc.
  72.  * Looking at additional bytes would require one of these approaches:
  73.  *     1) assume we can fseek() the input file (fails for piped input);
  74.  *     2) assume we can push back more than one character (works in
  75.  *        some C implementations, but unportable);
  76.  *     3) provide our own buffering as is done in djpeg (breaks input readers
  77.  *        that want to use stdio directly, such as the RLE library);
  78.  * or  4) don't put back the data, and modify the input_init methods to assume
  79.  *        they start reading after the start of file (also breaks RLE library).
  80.  * #1 is attractive for MS-DOS but is untenable on Unix.
  81.  *
  82.  * The most portable solution for file types that can't be identified by their
  83.  * first byte is to make the user tell us what they are.  This is also the
  84.  * only approach for "raw" file types that contain only arbitrary values.
  85.  * We presently apply this method for Targa files.  Most of the time Targa
  86.  * files start with 0x00, so we recognize that case.  Potentially, however,
  87.  * a Targa file could start with any byte value (byte 0 is the length of the
  88.  * seldom-used ID field), so we provide a switch to force Targa input mode.
  89.  */
  90.  
  91. static boolean is_targa;    /* records user -targa switch */
  92.  
  93.  
  94. LOCAL void
  95. select_file_type (compress_info_ptr cinfo)
  96. {
  97.   int c;
  98.  
  99.   if (is_targa) {
  100. #ifdef TARGA_SUPPORTED
  101.     jselrtarga(cinfo);
  102. #else
  103.     ERREXIT(cinfo->emethods, "Targa support was not compiled");
  104. #endif
  105.     return;
  106.   }
  107.  
  108.   if ((c = getc(cinfo->input_file)) == EOF)
  109.     ERREXIT(cinfo->emethods, "Empty input file");
  110.  
  111.   switch (c) {
  112. #ifdef GIF_SUPPORTED
  113.   case 'G':
  114.     jselrgif(cinfo);
  115.     break;
  116. #endif
  117. #ifdef PPM_SUPPORTED
  118.   case 'P':
  119.     jselrppm(cinfo);
  120.     break;
  121. #endif
  122. #ifdef RLE_SUPPORTED
  123.   case 'R':
  124.     jselrrle(cinfo);
  125.     break;
  126. #endif
  127. #ifdef TARGA_SUPPORTED
  128.   case 0x00:
  129.     jselrtarga(cinfo);
  130.     break;
  131. #endif
  132.   default:
  133. #ifdef TARGA_SUPPORTED
  134.     ERREXIT(cinfo->emethods, "Unrecognized input file format --- perhaps you need -targa");
  135. #else
  136.     ERREXIT(cinfo->emethods, "Unrecognized input file format");
  137. #endif
  138.     break;
  139.   }
  140.  
  141.   if (ungetc(c, cinfo->input_file) == EOF)
  142.     ERREXIT(cinfo->emethods, "ungetc failed");
  143. }
  144.  
  145.  
  146. /*
  147.  * This routine gets control after the input file header has been read.
  148.  * It must determine what output JPEG file format is to be written,
  149.  * and make any other compression parameter changes that are desirable.
  150.  */
  151.  
  152. METHODDEF void
  153. c_ui_method_selection (compress_info_ptr cinfo)
  154. {
  155.   /* If the input is gray scale, generate a monochrome JPEG file. */
  156.   if (cinfo->in_color_space == CS_GRAYSCALE)
  157.     j_monochrome_default(cinfo);
  158.   /* For now, always select JFIF output format. */
  159. #ifdef JFIF_SUPPORTED
  160.   jselwjfif(cinfo);
  161. #else
  162.   You shoulda defined JFIF_SUPPORTED.   /* deliberate syntax error */
  163. #endif
  164. }
  165.  
  166.  
  167. /*
  168.  * Signal catcher to ensure that temporary files are removed before aborting.
  169.  * NB: for Amiga Manx C this is actually a global routine named _abort();
  170.  * see -Dsignal_catcher=_abort in CFLAGS.  Talk about bogus...
  171.  */
  172.  
  173. #ifdef NEED_SIGNAL_CATCHER
  174.  
  175. static external_methods_ptr emethods; /* for access to free_all */
  176.  
  177. GLOBAL void
  178. signal_catcher (int signum)
  179. {
  180.   if (emethods != NULL) {
  181.     emethods->trace_level = 0;    /* turn off trace output */
  182.     (*emethods->free_all) ();    /* clean up memory allocation & temp files */
  183.   }
  184.   exit(EXIT_FAILURE);
  185. }
  186.  
  187. #endif
  188.  
  189.  
  190. /*
  191.  * Optional routine to display a percent-done figure on stderr.
  192.  * See jcdeflts.c for explanation of the information used.
  193.  */
  194.  
  195. #ifdef PROGRESS_REPORT
  196.  
  197. METHODDEF void
  198. progress_monitor (compress_info_ptr cinfo, long loopcounter, long looplimit)
  199. {
  200.   if (cinfo->total_passes > 1) {
  201.     fprintf(stderr, "\rPass %d/%d: %3d%% ",
  202.         cinfo->completed_passes+1, cinfo->total_passes,
  203.         (int) (loopcounter*100L/looplimit));
  204.   } else {
  205.     fprintf(stderr, "\r %3d%% ",
  206.         (int) (loopcounter*100L/looplimit));
  207.   }
  208.   fflush(stderr);
  209. }
  210.  
  211. #endif
  212.  
  213.  
  214. /*
  215.  * Argument-parsing code.
  216.  * The switch parser is designed to be useful with DOS-style command line
  217.  * syntax, ie, intermixed switches and file names, where only the switches
  218.  * to the left of a given file name affect processing of that file.
  219.  * The main program in this file doesn't actually use this capability...
  220.  */
  221.  
  222.  
  223. static char * progname;        /* program name for error messages */
  224. static char * outfilename;    /* for -outfile switch */
  225.  
  226.  
  227. LOCAL void
  228. usage (void)
  229. /* complain about bad command line */
  230. {
  231.   fprintf(stderr, "usage: %s [switches] ", progname);
  232. #ifdef TWO_FILE_COMMANDLINE
  233.   fprintf(stderr, "inputfile outputfile\n");
  234. #else
  235.   fprintf(stderr, "[inputfile]\n");
  236. #endif
  237.  
  238.   fprintf(stderr, "Switches (names may be abbreviated):\n");
  239.   fprintf(stderr, "  -quality N     Compression quality (0..100; 5-95 is useful range)\n");
  240.   fprintf(stderr, "  -grayscale     Create monochrome JPEG file\n");
  241. #ifdef ENTROPY_OPT_SUPPORTED
  242.   fprintf(stderr, "  -optimize      Optimize Huffman table (smaller file, but slow compression)\n");
  243. #endif
  244. #ifdef TARGA_SUPPORTED
  245.   fprintf(stderr, "  -targa         Input file is Targa format (usually not needed)\n");
  246. #endif
  247.   fprintf(stderr, "Switches for advanced users:\n");
  248.   fprintf(stderr, "  -restart N     Set restart interval in rows, or in blocks with B\n");
  249. #ifdef INPUT_SMOOTHING_SUPPORTED
  250.   fprintf(stderr, "  -smooth N      Smooth dithered input (N=1..100 is strength)\n");
  251. #endif
  252.   fprintf(stderr, "  -maxmemory N   Maximum memory to use (in kbytes)\n");
  253.   fprintf(stderr, "  -verbose  or  -debug   Emit debug output\n");
  254.   fprintf(stderr, "Switches for wizards:\n");
  255. #ifdef C_ARITH_CODING_SUPPORTED
  256.   fprintf(stderr, "  -arithmetic    Use arithmetic coding\n");
  257. #endif
  258. #ifdef C_MULTISCAN_FILES_SUPPORTED
  259.   fprintf(stderr, "  -nointerleave  Create noninterleaved JPEG file\n");
  260. #endif
  261.   fprintf(stderr, "  -qtables file  Use quantization tables given in file\n");
  262.   fprintf(stderr, "  -sample HxV[,...]  Set JPEG sampling factors\n");
  263.   exit(EXIT_FAILURE);
  264. }
  265.  
  266.  
  267. LOCAL boolean
  268. keymatch (char * arg, const char * keyword, int minchars)
  269. /* Case-insensitive matching of (possibly abbreviated) keyword switches. */
  270. /* keyword is the constant keyword (must be lower case already), */
  271. /* minchars is length of minimum legal abbreviation. */
  272. {
  273.   register int ca, ck;
  274.   register int nmatched = 0;
  275.  
  276.   while ((ca = *arg++) != '\0') {
  277.     if ((ck = *keyword++) == '\0')
  278.       return FALSE;        /* arg longer than keyword, no good */
  279.     if (isupper(ca))        /* force arg to lcase (assume ck is already) */
  280.       ca = tolower(ca);
  281.     if (ca != ck)
  282.       return FALSE;        /* no good */
  283.     nmatched++;            /* count matched characters */
  284.   }
  285.   /* reached end of argument; fail if it's too short for unique abbrev */
  286.   if (nmatched < minchars)
  287.     return FALSE;
  288.   return TRUE;            /* A-OK */
  289. }
  290.  
  291.  
  292. LOCAL int
  293. qt_getc (FILE * file)
  294. /* Read next char, skipping over any comments (# to end of line) */
  295. /* A comment/newline sequence is returned as a newline */
  296. {
  297.   register int ch;
  298.   
  299.   ch = getc(file);
  300.   if (ch == '#') {
  301.     do {
  302.       ch = getc(file);
  303.     } while (ch != '\n' && ch != EOF);
  304.   }
  305.   return ch;
  306. }
  307.  
  308.  
  309. LOCAL long
  310. read_qt_integer (FILE * file)
  311. /* Read an unsigned decimal integer from a quantization-table file */
  312. /* Swallows one trailing character after the integer */
  313. {
  314.   register int ch;
  315.   register long val;
  316.   
  317.   /* Skip any leading whitespace, detect EOF */
  318.   do {
  319.     ch = qt_getc(file);
  320.     if (ch == EOF)
  321.       return EOF;
  322.   } while (isspace(ch));
  323.   
  324.   if (! isdigit(ch)) {
  325.     fprintf(stderr, "%s: bogus data in quantization file\n", progname);
  326.     exit(EXIT_FAILURE);
  327.   }
  328.  
  329.   val = ch - '0';
  330.   while (ch = qt_getc(file), isdigit(ch)) {
  331.     val *= 10;
  332.     val += ch - '0';
  333.   }
  334.   return val;
  335. }
  336.  
  337.  
  338. LOCAL void
  339. read_quant_tables (compress_info_ptr cinfo, char * filename, int scale_factor)
  340. /* Read a set of quantization tables from the specified file.
  341.  * The file is plain ASCII text: decimal numbers with whitespace between.
  342.  * Comments preceded by '#' may be included in the file.
  343.  * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values.
  344.  * The tables are implicitly numbered 0,1,etc.
  345.  */
  346. {
  347.   /* ZIG[i] is the zigzag-order position of the i'th element of a DCT block */
  348.   /* read in natural order (left to right, top to bottom). */
  349.   static const short ZIG[DCTSIZE2] = {
  350.      0,  1,  5,  6, 14, 15, 27, 28,
  351.      2,  4,  7, 13, 16, 26, 29, 42,
  352.      3,  8, 12, 17, 25, 30, 41, 43,
  353.      9, 11, 18, 24, 31, 40, 44, 53,
  354.     10, 19, 23, 32, 39, 45, 52, 54,
  355.     20, 22, 33, 38, 46, 51, 55, 60,
  356.     21, 34, 37, 47, 50, 56, 59, 61,
  357.     35, 36, 48, 49, 57, 58, 62, 63
  358.     };
  359.   FILE * fp;
  360.   int tblno, i;
  361.   long val;
  362.   QUANT_TBL table;
  363.  
  364.   if ((fp = fopen(filename, "r")) == NULL) {
  365.     fprintf(stderr, "%s: can't open %s\n", progname, filename);
  366.     exit(EXIT_FAILURE);
  367.   }
  368.   tblno = 0;
  369.  
  370.   while ((val = read_qt_integer(fp)) != EOF) { /* read 1st element of table */
  371.     if (tblno >= NUM_QUANT_TBLS) {
  372.       fprintf(stderr, "%s: too many tables in file %s\n", progname, filename);
  373.       exit(EXIT_FAILURE);
  374.     }
  375.     table[0] = (QUANT_VAL) val;
  376.     for (i = 1; i < DCTSIZE2; i++) {
  377.       if ((val = read_qt_integer(fp)) == EOF) {
  378.     fprintf(stderr, "%s: incomplete table in file %s\n", progname, filename);
  379.     exit(EXIT_FAILURE);
  380.       }
  381.       table[ZIG[i]] = (QUANT_VAL) val;
  382.     }
  383.     j_add_quant_table(cinfo, tblno, table, scale_factor, FALSE);
  384.     tblno++;
  385.   }
  386.  
  387.   fclose(fp);
  388. }
  389.  
  390.  
  391. LOCAL void
  392. set_sample_factors (compress_info_ptr cinfo, char *arg)
  393. /* Process a sample-factors parameter string, of the form */
  394. /*     HxV[,HxV,...]    */
  395. {
  396. #define MAX_COMPONENTS 4    /* # of comp_info slots made by jcdeflts.c */
  397.   int ci, val1, val2;
  398.   char ch1, ch2;
  399.  
  400.   for (ci = 0; ci < MAX_COMPONENTS; ci++) {
  401.     if (*arg) {
  402.       ch2 = ',';        /* if not set by sscanf, will be ',' */
  403.       if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3)
  404.     usage();
  405.       if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',')
  406.     usage();        /* syntax check */
  407.       if (val1 <= 0 || val1 > 4 || val2 <= 0 || val2 > 4) {
  408.     fprintf(stderr, "JPEG sampling factors must be 1..4\n");
  409.     exit(EXIT_FAILURE);
  410.       }
  411.       cinfo->comp_info[ci].h_samp_factor = val1;
  412.       cinfo->comp_info[ci].v_samp_factor = val2;
  413.       while (*arg && *arg++ != ',') /* advance to next segment of arg string */
  414.     ;
  415.     } else {
  416.       /* reached end of parameter, set remaining components to 1x1 sampling */
  417.       cinfo->comp_info[ci].h_samp_factor = 1;
  418.       cinfo->comp_info[ci].v_samp_factor = 1;
  419.     }
  420.   }
  421. }
  422.  
  423.  
  424. LOCAL int
  425. parse_switches (compress_info_ptr cinfo, int last_file_arg_seen,
  426.         int argc, char **argv)
  427. /* Initialize cinfo with default switch settings, then parse option switches.
  428.  * Returns argv[] index of first file-name argument (== argc if none).
  429.  * Any file names with indexes <= last_file_arg_seen are ignored;
  430.  * they have presumably been processed in a previous iteration.
  431.  * (Pass 0 for last_file_arg_seen on the first or only iteration.)
  432.  */
  433. {
  434.   int argn;
  435.   char * arg;
  436.   char * qtablefile = NULL;    /* saves -qtables filename if any */
  437.   int q_scale_factor = 100;    /* default to no scaling for -qtables */
  438.  
  439.   /* (Re-)initialize the system-dependent error and memory managers. */
  440.   jselerror(cinfo->emethods);    /* error/trace message routines */
  441.   jselmemmgr(cinfo->emethods);    /* memory allocation routines */
  442.   cinfo->methods->c_ui_method_selection = c_ui_method_selection;
  443.  
  444.   /* Now OK to enable signal catcher. */
  445. #ifdef NEED_SIGNAL_CATCHER
  446.   emethods = cinfo->emethods;
  447. #endif
  448.  
  449.   /* Set up default JPEG parameters. */
  450.   /* Note that default -quality level here need not, and does not,
  451.    * match the default scaling for an explicit -qtables argument.
  452.    */
  453.   j_c_defaults(cinfo, 75, FALSE); /* default quality level = 75 */
  454.   is_targa = FALSE;
  455.   outfilename = NULL;
  456.  
  457.   /* Scan command line options, adjust parameters */
  458.  
  459.   for (argn = 1; argn < argc; argn++) {
  460.     arg = argv[argn];
  461.     if (*arg != '-') {
  462.       /* Not a switch, must be a file name argument */
  463.       if (argn <= last_file_arg_seen) {
  464.     outfilename = NULL;    /* -outfile applies to just one input file */
  465.     continue;        /* ignore this name if previously processed */
  466.       }
  467.       break;            /* else done parsing switches */
  468.     }
  469.     arg++;            /* advance past switch marker character */
  470.  
  471.     if (keymatch(arg, "arithmetic", 1)) {
  472.       /* Use arithmetic coding. */
  473. #ifdef C_ARITH_CODING_SUPPORTED
  474.       cinfo->arith_code = TRUE;
  475. #else
  476.       fprintf(stderr, "%s: sorry, arithmetic coding not supported\n",
  477.           progname);
  478.       exit(EXIT_FAILURE);
  479. #endif
  480.  
  481.     } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
  482.       /* Enable debug printouts. */
  483.       /* On first -d, print version identification */
  484.       if (last_file_arg_seen == 0 && cinfo->emethods->trace_level == 0)
  485.     fprintf(stderr, "Independent JPEG Group's CJPEG, version %s\n%s\n",
  486.         JVERSION, JCOPYRIGHT);
  487.       cinfo->emethods->trace_level++;
  488.  
  489.     } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) {
  490.       /* Force a monochrome JPEG file to be generated. */
  491.       j_monochrome_default(cinfo);
  492.  
  493.     } else if (keymatch(arg, "maxmemory", 1)) {
  494.       /* Maximum memory in Kb (or Mb with 'm'). */
  495.       long lval;
  496.       char ch = 'x';
  497.  
  498.       if (++argn >= argc)    /* advance to next argument */
  499.     usage();
  500.       if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
  501.     usage();
  502.       if (ch == 'm' || ch == 'M')
  503.     lval *= 1000L;
  504.       cinfo->emethods->max_memory_to_use = lval * 1000L;
  505.  
  506.     } else if (keymatch(arg, "nointerleave", 3)) {
  507.       /* Create noninterleaved file. */
  508. #ifdef C_MULTISCAN_FILES_SUPPORTED
  509.       cinfo->interleave = FALSE;
  510. #else
  511.       fprintf(stderr, "%s: sorry, multiple-scan support was not compiled\n",
  512.           progname);
  513.       exit(EXIT_FAILURE);
  514. #endif
  515.  
  516.     } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) {
  517.       /* Enable entropy parm optimization. */
  518. #ifdef ENTROPY_OPT_SUPPORTED
  519.       cinfo->optimize_coding = TRUE;
  520. #else
  521.       fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n",
  522.           progname);
  523.       exit(EXIT_FAILURE);
  524. #endif
  525.  
  526.     } else if (keymatch(arg, "outfile", 3)) {
  527.       /* Set output file name. */
  528.       if (++argn >= argc)    /* advance to next argument */
  529.     usage();
  530.       outfilename = argv[argn];    /* save it away for later use */
  531.  
  532.     } else if (keymatch(arg, "quality", 1)) {
  533.       /* Quality factor (quantization table scaling factor). */
  534.       int val;
  535.  
  536.       if (++argn >= argc)    /* advance to next argument */
  537.     usage();
  538.       if (sscanf(argv[argn], "%d", &val) != 1)
  539.     usage();
  540.       /* Set quantization tables (will be overridden if -qtables also given).
  541.        * Note: we make force_baseline FALSE.
  542.        * This means non-baseline JPEG files can be created with low Q values.
  543.        * To ensure only baseline files are generated, pass TRUE instead.
  544.        */
  545.       j_set_quality(cinfo, val, FALSE);
  546.       /* Change scale factor in case -qtables is present. */
  547.       q_scale_factor = j_quality_scaling(val);
  548.  
  549.     } else if (keymatch(arg, "qtables", 2)) {
  550.       /* Quantization tables fetched from file. */
  551.       if (++argn >= argc)    /* advance to next argument */
  552.     usage();
  553.       qtablefile = argv[argn];
  554.       /* we postpone actually reading the file in case -quality comes later */
  555.  
  556.     } else if (keymatch(arg, "restart", 1)) {
  557.       /* Restart interval in MCU rows (or in MCUs with 'b'). */
  558.       long lval;
  559.       char ch = 'x';
  560.  
  561.       if (++argn >= argc)    /* advance to next argument */
  562.     usage();
  563.       if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
  564.     usage();
  565.       if (lval < 0 || lval > 65535L)
  566.     usage();
  567.       if (ch == 'b' || ch == 'B')
  568.     cinfo->restart_interval = (UINT16) lval;
  569.       else
  570.     cinfo->restart_in_rows = (int) lval;
  571.  
  572.     } else if (keymatch(arg, "sample", 2)) {
  573.       /* Set sampling factors. */
  574.       if (++argn >= argc)    /* advance to next argument */
  575.     usage();
  576.       set_sample_factors(cinfo, argv[argn]);
  577.  
  578.     } else if (keymatch(arg, "smooth", 2)) {
  579.       /* Set input smoothing factor. */
  580.       int val;
  581.  
  582.       if (++argn >= argc)    /* advance to next argument */
  583.     usage();
  584.       if (sscanf(argv[argn], "%d", &val) != 1)
  585.     usage();
  586.       if (val < 0 || val > 100)
  587.     usage();
  588.       cinfo->smoothing_factor = val;
  589.  
  590.     } else if (keymatch(arg, "targa", 1)) {
  591.       /* Input file is Targa format. */
  592.       is_targa = TRUE;
  593.  
  594.     } else {
  595.       usage();            /* bogus switch */
  596.     }
  597.   }
  598.  
  599.   /* Post-switch-scanning cleanup */
  600.  
  601.   if (qtablefile != NULL)    /* process -qtables if it was present */
  602.     read_quant_tables(cinfo, qtablefile, q_scale_factor);
  603.  
  604.   return argn;            /* return index of next arg (file name) */
  605. }
  606.  
  607.  
  608. /*
  609.  * The main program.
  610.  */
  611.  
  612. GLOBAL int
  613. main (int argc, char **argv)
  614. {
  615.   struct Compress_info_struct cinfo;
  616.   struct Compress_methods_struct c_methods;
  617.   struct External_methods_struct e_methods;
  618.   int file_index;
  619.  
  620.   /* On Mac, fetch a command line. */
  621. #ifdef THINK_C
  622.   argc = ccommand(&argv);
  623. #endif
  624.  
  625.   progname = argv[0];
  626.  
  627.   /* Set up links to method structures. */
  628.   cinfo.methods = &c_methods;
  629.   cinfo.emethods = &e_methods;
  630.  
  631.   /* Install, but don't yet enable signal catcher. */
  632. #ifdef NEED_SIGNAL_CATCHER
  633.   emethods = NULL;
  634.   signal(SIGINT, signal_catcher);
  635. #ifdef SIGTERM            /* not all systems have SIGTERM */
  636.   signal(SIGTERM, signal_catcher);
  637. #endif
  638. #endif
  639.  
  640.   /* Scan command line: set up compression parameters, find file names. */
  641.  
  642.   file_index = parse_switches(&cinfo, 0, argc, argv);
  643.  
  644. #ifdef TWO_FILE_COMMANDLINE
  645.   /* Must have either -outfile switch or explicit output file name */
  646.   if (outfilename == NULL) {
  647.     if (file_index != argc-2) {
  648.       fprintf(stderr, "%s: must name one input and one output file\n",
  649.           progname);
  650.       usage();
  651.     }
  652.     outfilename = argv[file_index+1];
  653.   } else {
  654.     if (file_index != argc-1) {
  655.       fprintf(stderr, "%s: must name one input and one output file\n",
  656.           progname);
  657.       usage();
  658.     }
  659.   }
  660. #else
  661.   /* Unix style: expect zero or one file name */
  662.   if (file_index < argc-1) {
  663.     fprintf(stderr, "%s: only one input file\n", progname);
  664.     usage();
  665.   }
  666. #endif /* TWO_FILE_COMMANDLINE */
  667.  
  668.   /* Open the input file. */
  669.   if (file_index < argc) {
  670.     if ((cinfo.input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
  671.       fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
  672.       exit(EXIT_FAILURE);
  673.     }
  674.   } else {
  675.     /* default input file is stdin */
  676. #ifdef USE_SETMODE        /* need to hack file mode? */
  677.     setmode(fileno(stdin), O_BINARY);
  678. #endif
  679. #ifdef USE_FDOPEN        /* need to re-open in binary mode? */
  680.     if ((cinfo.input_file = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
  681.       fprintf(stderr, "%s: can't open stdin\n", progname);
  682.       exit(EXIT_FAILURE);
  683.     }
  684. #else
  685.     cinfo.input_file = stdin;
  686. #endif
  687.   }
  688.  
  689.   /* Open the output file. */
  690.   if (outfilename != NULL) {
  691.     if ((cinfo.output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
  692.       fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
  693.       exit(EXIT_FAILURE);
  694.     }
  695.   } else {
  696.     /* default output file is stdout */
  697. #ifdef USE_SETMODE        /* need to hack file mode? */
  698.     setmode(fileno(stdout), O_BINARY);
  699. #endif
  700. #ifdef USE_FDOPEN        /* need to re-open in binary mode? */
  701.     if ((cinfo.output_file = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) {
  702.       fprintf(stderr, "%s: can't open stdout\n", progname);
  703.       exit(EXIT_FAILURE);
  704.     }
  705. #else
  706.     cinfo.output_file = stdout;
  707. #endif
  708.   }
  709.  
  710.   /* Figure out the input file format, and set up to read it. */
  711.   select_file_type(&cinfo);
  712.  
  713. #ifdef PROGRESS_REPORT
  714.   /* Start up progress display, unless trace output is on */
  715.   if (e_methods.trace_level == 0)
  716.     c_methods.progress_monitor = progress_monitor;
  717. #endif
  718.  
  719.   /* Do it to it! */
  720.   jpeg_compress(&cinfo);
  721.  
  722. #ifdef PROGRESS_REPORT
  723.   /* Clear away progress display */
  724.   if (e_methods.trace_level == 0) {
  725.     fprintf(stderr, "\r                \r");
  726.     fflush(stderr);
  727.   }
  728. #endif
  729.  
  730.   /* All done. */
  731.   exit(EXIT_SUCCESS);
  732.   return 0;            /* suppress no-return-value warnings */
  733. }
  734.