home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / GRAPHICS / jpeglib_5a.lzh / JPEG_5A / cjpeg.c < prev    next >
Text File  |  1995-01-20  |  28KB  |  912 lines

  1. /*
  2.  * cjpeg.c
  3.  *
  4.  * Copyright (C) 1991-1994, 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 "cdjpeg.h"        /* Common decls for cjpeg/djpeg applications */
  27. #include "jversion.h"        /* for version message */
  28.  
  29. #ifdef OSK
  30. #include <sgstat.h>
  31. #endif
  32.  
  33. #include <ctype.h>        /* to declare isupper(), tolower() */
  34. #ifdef NEED_SIGNAL_CATCHER
  35. #include <signal.h>        /* to declare signal() */
  36. #endif
  37. #ifdef USE_SETMODE
  38. #include <fcntl.h>        /* to declare setmode()'s parameter macros */
  39. /* If you have setmode() but not <io.h>, just delete this line: */
  40. #include <io.h>            /* to declare setmode() */
  41. #endif
  42.  
  43. #ifdef USE_CCOMMAND        /* command-line reader for Macintosh */
  44. #ifdef __MWERKS__
  45. #include <SIOUX.h>              /* Metrowerks declares it here */
  46. #endif
  47. #ifdef THINK_C
  48. #include <console.h>        /* Think declares it here */
  49. #endif
  50. #endif
  51.  
  52. #ifdef DONT_USE_B_MODE        /* define mode parameters for fopen() */
  53. #define READ_BINARY    "r"
  54. #define WRITE_BINARY    "w"
  55. #else
  56. #define READ_BINARY    "rb"
  57. #define WRITE_BINARY    "wb"
  58. #endif
  59.  
  60. #ifndef EXIT_FAILURE        /* define exit() codes if not provided */
  61. #define EXIT_FAILURE  1
  62. #endif
  63. #ifndef EXIT_SUCCESS
  64. #ifdef VMS
  65. #define EXIT_SUCCESS  1        /* VMS is very nonstandard */
  66. #else
  67. #define EXIT_SUCCESS  0
  68. #endif
  69. #endif
  70. #ifndef EXIT_WARNING
  71. #ifdef VMS
  72. #define EXIT_WARNING  1        /* VMS is very nonstandard */
  73. #else
  74. #define EXIT_WARNING  2
  75. #endif
  76. #endif
  77.  
  78.  
  79. /* Create the add-on message string table. */
  80.  
  81. #define JMESSAGE(code,string)    string ,
  82.  
  83. static const char * const cdjpeg_message_table[] = {
  84. #include "cderror.h"
  85.   NULL
  86. };
  87.  
  88.  
  89. /*
  90.  * This routine determines what format the input file is,
  91.  * and selects the appropriate input-reading module.
  92.  *
  93.  * To determine which family of input formats the file belongs to,
  94.  * we may look only at the first byte of the file, since C does not
  95.  * guarantee that more than one character can be pushed back with ungetc.
  96.  * Looking at additional bytes would require one of these approaches:
  97.  *     1) assume we can fseek() the input file (fails for piped input);
  98.  *     2) assume we can push back more than one character (works in
  99.  *        some C implementations, but unportable);
  100.  *     3) provide our own buffering (breaks input readers that want to use
  101.  *        stdio directly, such as the RLE library);
  102.  * or  4) don't put back the data, and modify the input_init methods to assume
  103.  *        they start reading after the start of file (also breaks RLE library).
  104.  * #1 is attractive for MS-DOS but is untenable on Unix.
  105.  *
  106.  * The most portable solution for file types that can't be identified by their
  107.  * first byte is to make the user tell us what they are.  This is also the
  108.  * only approach for "raw" file types that contain only arbitrary values.
  109.  * We presently apply this method for Targa files.  Most of the time Targa
  110.  * files start with 0x00, so we recognize that case.  Potentially, however,
  111.  * a Targa file could start with any byte value (byte 0 is the length of the
  112.  * seldom-used ID field), so we provide a switch to force Targa input mode.
  113.  */
  114.  
  115. static boolean is_targa;    /* records user -targa switch */
  116.  
  117.  
  118. LOCAL cjpeg_source_ptr
  119. select_file_type (j_compress_ptr cinfo, FILE * infile)
  120. {
  121.   int c;
  122.  
  123.   if (is_targa) {
  124. #ifdef TARGA_SUPPORTED
  125.     return jinit_read_targa(cinfo);
  126. #else
  127.     ERREXIT(cinfo, JERR_TGA_NOTCOMP);
  128. #endif
  129.   }
  130.  
  131.   if ((c = getc(infile)) == EOF)
  132.     ERREXIT(cinfo, JERR_INPUT_EMPTY);
  133.   if (ungetc(c, infile) == EOF)
  134.     ERREXIT(cinfo, JERR_UNGETC_FAILED);
  135.  
  136.   switch (c) {
  137. #ifdef BMP_SUPPORTED
  138.   case 'B':
  139.     return jinit_read_bmp(cinfo);
  140. #endif
  141. #ifdef GIF_SUPPORTED
  142.   case 'G':
  143.     return jinit_read_gif(cinfo);
  144. #endif
  145. #ifdef PPM_SUPPORTED
  146.   case 'P':
  147.     return jinit_read_ppm(cinfo);
  148. #endif
  149. #ifdef RLE_SUPPORTED
  150.   case 'R':
  151.     return jinit_read_rle(cinfo);
  152. #endif
  153. #ifdef TARGA_SUPPORTED
  154.   case 0x00:
  155.     return jinit_read_targa(cinfo);
  156. #endif
  157.   default:
  158.     ERREXIT(cinfo, JERR_UNKNOWN_FORMAT);
  159.     break;
  160.   }
  161.  
  162.   return NULL;            /* suppress compiler warnings */
  163. }
  164.  
  165.  
  166. /*
  167.  * Signal catcher to ensure that temporary files are removed before aborting.
  168.  * NB: for Amiga Manx C this is actually a global routine named _abort();
  169.  * we put "#define signal_catcher _abort" in jconfig.h.  Talk about bogus...
  170.  */
  171.  
  172. #ifdef NEED_SIGNAL_CATCHER
  173.  
  174. static j_common_ptr sig_cinfo;
  175.  
  176. GLOBAL void
  177. signal_catcher (int signum)
  178. {
  179.   if (sig_cinfo != NULL) {
  180.     if (sig_cinfo->err != NULL) /* turn off trace output */
  181.       sig_cinfo->err->trace_level = 0;
  182.     jpeg_destroy(sig_cinfo);    /* 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.  */
  193.  
  194. #ifdef PROGRESS_REPORT
  195.  
  196. METHODDEF void
  197. progress_monitor (j_common_ptr cinfo)
  198. {
  199.   cd_progress_ptr prog = (cd_progress_ptr) cinfo->progress;
  200.   int total_passes = prog->pub.total_passes + prog->total_extra_passes;
  201.   int percent_done = (int) (prog->pub.pass_counter*100L/prog->pub.pass_limit);
  202.  
  203.   if (percent_done != prog->percent_done) {
  204.     prog->percent_done = percent_done;
  205.     if (total_passes > 1) {
  206.       fprintf(stderr, "\rPass %d/%d: %3d%% ",
  207.           prog->pub.completed_passes + prog->completed_extra_passes + 1,
  208.           total_passes, percent_done);
  209.     } else {
  210.       fprintf(stderr, "\r %3d%% ", percent_done);
  211.     }
  212.     fflush(stderr);
  213.   }
  214. }
  215.  
  216. #endif
  217.  
  218.  
  219. /*
  220.  * Argument-parsing code.
  221.  * The switch parser is designed to be useful with DOS-style command line
  222.  * syntax, ie, intermixed switches and file names, where only the switches
  223.  * to the left of a given file name affect processing of that file.
  224.  * The main program in this file doesn't actually use this capability...
  225.  */
  226.  
  227.  
  228. static const char * progname;    /* program name for error messages */
  229. static char * outfilename;    /* for -outfile switch */
  230.  
  231.  
  232. LOCAL void
  233. usage (void)
  234. /* complain about bad command line */
  235. {
  236.   fprintf(stderr, "usage: %s [switches] ", progname);
  237. #ifdef TWO_FILE_COMMANDLINE
  238.   fprintf(stderr, "inputfile outputfile\n");
  239. #else
  240.   fprintf(stderr, "[inputfile]\n");
  241. #endif
  242.  
  243.   fprintf(stderr, "Switches (names may be abbreviated):\n");
  244.   fprintf(stderr, "  -quality N     Compression quality (0..100; 5-95 is useful range)\n");
  245.   fprintf(stderr, "  -grayscale     Create monochrome JPEG file\n");
  246. #ifdef ENTROPY_OPT_SUPPORTED
  247.   fprintf(stderr, "  -optimize      Optimize Huffman table (smaller file, but slow compression)\n");
  248. #endif
  249. #ifdef TARGA_SUPPORTED
  250.   fprintf(stderr, "  -targa         Input file is Targa format (usually not needed)\n");
  251. #endif
  252.   fprintf(stderr, "Switches for advanced users:\n");
  253. #ifdef DCT_ISLOW_SUPPORTED
  254.   fprintf(stderr, "  -dct int       Use integer DCT method%s\n",
  255.       (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : ""));
  256. #endif
  257. #ifdef DCT_IFAST_SUPPORTED
  258.   fprintf(stderr, "  -dct fast      Use fast integer DCT (less accurate)%s\n",
  259.       (JDCT_DEFAULT == JDCT_IFAST ? " (default)" : ""));
  260. #endif
  261. #ifdef DCT_FLOAT_SUPPORTED
  262.   fprintf(stderr, "  -dct float     Use floating-point DCT method%s\n",
  263.       (JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : ""));
  264. #endif
  265.   fprintf(stderr, "  -restart N     Set restart interval in rows, or in blocks with B\n");
  266. #ifdef INPUT_SMOOTHING_SUPPORTED
  267.   fprintf(stderr, "  -smooth N      Smooth dithered input (N=1..100 is strength)\n");
  268. #endif
  269.   fprintf(stderr, "  -maxmemory N   Maximum memory to use (in kbytes)\n");
  270.   fprintf(stderr, "  -outfile name  Specify name for output file\n");
  271.   fprintf(stderr, "  -verbose  or  -debug   Emit debug output\n");
  272.   fprintf(stderr, "Switches for wizards:\n");
  273. #ifdef C_ARITH_CODING_SUPPORTED
  274.   fprintf(stderr, "  -arithmetic    Use arithmetic coding\n");
  275. #endif
  276.   fprintf(stderr, "  -baseline      Force baseline output\n");
  277. #ifdef C_MULTISCAN_FILES_SUPPORTED
  278.   fprintf(stderr, "  -nointerleave  Create noninterleaved JPEG file\n");
  279. #endif
  280.   fprintf(stderr, "  -qtables file  Use quantization tables given in file\n");
  281.   fprintf(stderr, "  -qslots N[,...]    Set component quantization tables\n");
  282.   fprintf(stderr, "  -sample HxV[,...]  Set component sampling factors\n");
  283.   exit(EXIT_FAILURE);
  284. }
  285.  
  286.  
  287. LOCAL boolean
  288. keymatch (char * arg, const char * keyword, int minchars)
  289. /* Case-insensitive matching of (possibly abbreviated) keyword switches. */
  290. /* keyword is the constant keyword (must be lower case already), */
  291. /* minchars is length of minimum legal abbreviation. */
  292. {
  293.   register int ca, ck;
  294.   register int nmatched = 0;
  295.  
  296.   while ((ca = *arg++) != '\0') {
  297.     if ((ck = *keyword++) == '\0')
  298.       return FALSE;        /* arg longer than keyword, no good */
  299.     if (isupper(ca))        /* force arg to lcase (assume ck is already) */
  300.       ca = tolower(ca);
  301.     if (ca != ck)
  302.       return FALSE;        /* no good */
  303.     nmatched++;            /* count matched characters */
  304.   }
  305.   /* reached end of argument; fail if it's too short for unique abbrev */
  306.   if (nmatched < minchars)
  307.     return FALSE;
  308.   return TRUE;            /* A-OK */
  309. }
  310.  
  311.  
  312. LOCAL int
  313. qt_getc (FILE * file)
  314. /* Read next char, skipping over any comments (# to end of line) */
  315. /* A comment/newline sequence is returned as a newline */
  316. {
  317.   register int ch;
  318.   
  319.   ch = getc(file);
  320.   if (ch == '#') {
  321.     do {
  322.       ch = getc(file);
  323.     } while (ch != '\n' && ch != EOF);
  324.   }
  325.   return ch;
  326. }
  327.  
  328.  
  329. LOCAL long
  330. read_qt_integer (FILE * file)
  331. /* Read an unsigned decimal integer from a quantization-table file */
  332. /* Swallows one trailing character after the integer */
  333. {
  334.   register int ch;
  335.   register long val;
  336.   
  337.   /* Skip any leading whitespace, detect EOF */
  338.   do {
  339.     ch = qt_getc(file);
  340.     if (ch == EOF)
  341.       return EOF;
  342.   } while (isspace(ch));
  343.   
  344.   if (! isdigit(ch)) {
  345.     fprintf(stderr, "%s: bogus data in quantization file\n", progname);
  346.     exit(EXIT_FAILURE);
  347.   }
  348.  
  349.   val = ch - '0';
  350.   while (ch = qt_getc(file), isdigit(ch)) {
  351.     val *= 10;
  352.     val += ch - '0';
  353.   }
  354.   return val;
  355. }
  356.  
  357.  
  358. LOCAL void
  359. read_quant_tables (j_compress_ptr cinfo, char * filename, int scale_factor,
  360.            boolean force_baseline)
  361. /* Read a set of quantization tables from the specified file.
  362.  * The file is plain ASCII text: decimal numbers with whitespace between.
  363.  * Comments preceded by '#' may be included in the file.
  364.  * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values.
  365.  * The tables are implicitly numbered 0,1,etc.
  366.  * NOTE: does not affect the qslots mapping, which will default to selecting
  367.  * table 0 for luminance (or primary) components, 1 for chrominance components.
  368.  * You must use -qslots if you want a different component->table mapping.
  369.  */
  370. {
  371.   /* ZIG[i] is the zigzag-order position of the i'th element of a DCT block */
  372.   /* read in natural order (left to right, top to bottom). */
  373.   static const int ZIG[DCTSIZE2] = {
  374.      0,  1,  5,  6, 14, 15, 27, 28,
  375.      2,  4,  7, 13, 16, 26, 29, 42,
  376.      3,  8, 12, 17, 25, 30, 41, 43,
  377.      9, 11, 18, 24, 31, 40, 44, 53,
  378.     10, 19, 23, 32, 39, 45, 52, 54,
  379.     20, 22, 33, 38, 46, 51, 55, 60,
  380.     21, 34, 37, 47, 50, 56, 59, 61,
  381.     35, 36, 48, 49, 57, 58, 62, 63
  382.     };
  383.   FILE * fp;
  384.   int tblno, i;
  385.   long val;
  386.   unsigned int table[DCTSIZE2];
  387.  
  388.   if ((fp = fopen(filename, "r")) == NULL) {
  389.     fprintf(stderr, "%s: can't open %s\n", progname, filename);
  390.     exit(EXIT_FAILURE);
  391.   }
  392.   tblno = 0;
  393.  
  394.   while ((val = read_qt_integer(fp)) != EOF) { /* read 1st element of table */
  395.     if (tblno >= NUM_QUANT_TBLS) {
  396.       fprintf(stderr, "%s: too many tables in file %s\n", progname, filename);
  397.       exit(EXIT_FAILURE);
  398.     }
  399.     table[0] = (unsigned int) val;
  400.     for (i = 1; i < DCTSIZE2; i++) {
  401.       if ((val = read_qt_integer(fp)) == EOF) {
  402.     fprintf(stderr, "%s: incomplete table in file %s\n", progname, filename);
  403.     exit(EXIT_FAILURE);
  404.       }
  405.       table[ZIG[i]] = (unsigned int) val;
  406.     }
  407.     jpeg_add_quant_table(cinfo, tblno, table, scale_factor, force_baseline);
  408.     tblno++;
  409.   }
  410.  
  411.   fclose(fp);
  412. }
  413.  
  414.  
  415. LOCAL void
  416. set_quant_slots (j_compress_ptr cinfo, char *arg)
  417. /* Process a quantization-table-selectors parameter string, of the form
  418.  *     N[,N,...]
  419.  * If there are more components than parameters, the last value is replicated.
  420.  */
  421. {
  422.   int val = 0;            /* default table # */
  423.   int ci;
  424.   char ch;
  425.  
  426.   for (ci = 0; ci < MAX_COMPONENTS; ci++) {
  427.     if (*arg) {
  428.       ch = ',';            /* if not set by sscanf, will be ',' */
  429.       if (sscanf(arg, "%d%c", &val, &ch) < 1)
  430.     usage();
  431.       if (ch != ',')
  432.     usage();        /* syntax check */
  433.       if (val < 0 || val >= NUM_QUANT_TBLS) {
  434.     fprintf(stderr, "JPEG quantization tables are numbered 0..%d\n",
  435.         NUM_QUANT_TBLS-1);
  436.     exit(EXIT_FAILURE);
  437.       }
  438.       cinfo->comp_info[ci].quant_tbl_no = val;
  439.       while (*arg && *arg++ != ',') /* advance to next segment of arg string */
  440.     ;
  441.     } else {
  442.       /* reached end of parameter, set remaining components to last table */
  443.       cinfo->comp_info[ci].quant_tbl_no = val;
  444.     }
  445.   }
  446. }
  447.  
  448.  
  449. LOCAL void
  450. set_sample_factors (j_compress_ptr cinfo, char *arg)
  451. /* Process a sample-factors parameter string, of the form
  452.  *     HxV[,HxV,...]
  453.  * If there are more components than parameters, "1x1" is assumed.
  454.  */
  455. {
  456.   int ci, val1, val2;
  457.   char ch1, ch2;
  458.  
  459.   for (ci = 0; ci < MAX_COMPONENTS; ci++) {
  460.     if (*arg) {
  461.       ch2 = ',';        /* if not set by sscanf, will be ',' */
  462.       if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3)
  463.     usage();
  464.       if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',')
  465.     usage();        /* syntax check */
  466.       if (val1 <= 0 || val1 > 4 || val2 <= 0 || val2 > 4) {
  467.     fprintf(stderr, "JPEG sampling factors must be 1..4\n");
  468.     exit(EXIT_FAILURE);
  469.       }
  470.       cinfo->comp_info[ci].h_samp_factor = val1;
  471.       cinfo->comp_info[ci].v_samp_factor = val2;
  472.       while (*arg && *arg++ != ',') /* advance to next segment of arg string */
  473.     ;
  474.     } else {
  475.       /* reached end of parameter, set remaining components to 1x1 sampling */
  476.       cinfo->comp_info[ci].h_samp_factor = 1;
  477.       cinfo->comp_info[ci].v_samp_factor = 1;
  478.     }
  479.   }
  480. }
  481.  
  482.  
  483. LOCAL int
  484. parse_switches (j_compress_ptr cinfo, int argc, char **argv,
  485.         int last_file_arg_seen, boolean for_real)
  486. /* Parse optional switches.
  487.  * Returns argv[] index of first file-name argument (== argc if none).
  488.  * Any file names with indexes <= last_file_arg_seen are ignored;
  489.  * they have presumably been processed in a previous iteration.
  490.  * (Pass 0 for last_file_arg_seen on the first or only iteration.)
  491.  * for_real is FALSE on the first (dummy) pass; we may skip any expensive
  492.  * processing.
  493.  */
  494. {
  495.   int argn;
  496.   char * arg;
  497.   int quality;            /* -quality parameter */
  498.   int q_scale_factor;        /* scaling percentage for -qtables */
  499.   boolean force_baseline;
  500.   char * qtablefile = NULL;    /* saves -qtables filename if any */
  501.   char * qslotsarg = NULL;    /* saves -qslots parm if any */
  502.   char * samplearg = NULL;    /* saves -sample parm if any */
  503.  
  504.   /* Set up default JPEG parameters. */
  505.   /* Note that default -quality level need not, and does not,
  506.    * match the default scaling for an explicit -qtables argument.
  507.    */
  508.   quality = 75;            /* default -quality value */
  509.   q_scale_factor = 100;        /* default to no scaling for -qtables */
  510.   force_baseline = FALSE;    /* by default, allow 16-bit quantizers */
  511.   is_targa = FALSE;
  512.   outfilename = NULL;
  513.   cinfo->err->trace_level = 0;
  514.  
  515.   /* Scan command line options, adjust parameters */
  516.  
  517.   for (argn = 1; argn < argc; argn++) {
  518.     arg = argv[argn];
  519.     if (*arg != '-') {
  520.       /* Not a switch, must be a file name argument */
  521.       if (argn <= last_file_arg_seen) {
  522.     outfilename = NULL;    /* -outfile applies to just one input file */
  523.     continue;        /* ignore this name if previously processed */
  524.       }
  525.       break;            /* else done parsing switches */
  526.     }
  527.     arg++;            /* advance past switch marker character */
  528.  
  529.     if (keymatch(arg, "arithmetic", 1)) {
  530.       /* Use arithmetic coding. */
  531. #ifdef C_ARITH_CODING_SUPPORTED
  532.       cinfo->arith_code = TRUE;
  533. #else
  534.       fprintf(stderr, "%s: sorry, arithmetic coding not supported\n",
  535.           progname);
  536.       exit(EXIT_FAILURE);
  537. #endif
  538.  
  539.     } else if (keymatch(arg, "baseline", 1)) {
  540.       /* Force baseline output (8-bit quantizer values). */
  541.       force_baseline = TRUE;
  542.  
  543.     } else if (keymatch(arg, "dct", 2)) {
  544.       /* Select DCT algorithm. */
  545.       if (++argn >= argc)    /* advance to next argument */
  546.     usage();
  547.       if (keymatch(argv[argn], "int", 1)) {
  548.     cinfo->dct_method = JDCT_ISLOW;
  549.       } else if (keymatch(argv[argn], "fast", 2)) {
  550.     cinfo->dct_method = JDCT_IFAST;
  551.       } else if (keymatch(argv[argn], "float", 2)) {
  552.     cinfo->dct_method = JDCT_FLOAT;
  553.       } else
  554.     usage();
  555.  
  556.     } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
  557.       /* Enable debug printouts. */
  558.       /* On first -d, print version identification */
  559.       static boolean printed_version = FALSE;
  560.  
  561.       if (! printed_version) {
  562.     fprintf(stderr, "Independent JPEG Group's CJPEG, version %s\n%s\n",
  563.         JVERSION, JCOPYRIGHT);
  564.     printed_version = TRUE;
  565.       }
  566.       cinfo->err->trace_level++;
  567.  
  568.     } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) {
  569.       /* Force a monochrome JPEG file to be generated. */
  570.       jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
  571.  
  572.     } else if (keymatch(arg, "maxmemory", 3)) {
  573.       /* Maximum memory in Kb (or Mb with 'm'). */
  574.       long lval;
  575.       char ch = 'x';
  576.  
  577.       if (++argn >= argc)    /* advance to next argument */
  578.     usage();
  579.       if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
  580.     usage();
  581.       if (ch == 'm' || ch == 'M')
  582.     lval *= 1000L;
  583.       cinfo->mem->max_memory_to_use = lval * 1000L;
  584.  
  585.     } else if (keymatch(arg, "nointerleave", 3)) {
  586.       /* Create noninterleaved file. */
  587. #ifdef C_MULTISCAN_FILES_SUPPORTED
  588.       cinfo->interleave = FALSE;
  589. #else
  590.       fprintf(stderr, "%s: sorry, multiple-scan support was not compiled\n",
  591.           progname);
  592.       exit(EXIT_FAILURE);
  593. #endif
  594.  
  595.     } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) {
  596.       /* Enable entropy parm optimization. */
  597. #ifdef ENTROPY_OPT_SUPPORTED
  598.       cinfo->optimize_coding = TRUE;
  599. #else
  600.       fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n",
  601.           progname);
  602.       exit(EXIT_FAILURE);
  603. #endif
  604.  
  605.     } else if (keymatch(arg, "outfile", 4)) {
  606.       /* Set output file name. */
  607.       if (++argn >= argc)    /* advance to next argument */
  608.     usage();
  609.       outfilename = argv[argn];    /* save it away for later use */
  610.  
  611.     } else if (keymatch(arg, "quality", 1)) {
  612.       /* Quality factor (quantization table scaling factor). */
  613.       if (++argn >= argc)    /* advance to next argument */
  614.     usage();
  615.       if (sscanf(argv[argn], "%d", &quality) != 1)
  616.     usage();
  617.       /* Change scale factor in case -qtables is present. */
  618.       q_scale_factor = jpeg_quality_scaling(quality);
  619.  
  620.     } else if (keymatch(arg, "qslots", 2)) {
  621.       /* Quantization table slot numbers. */
  622.       if (++argn >= argc)    /* advance to next argument */
  623.     usage();
  624.       qslotsarg = argv[argn];
  625.       /* Must delay setting qslots until after we have processed any
  626.        * colorspace-determining switches, since jpeg_set_colorspace sets
  627.        * default quant table numbers.
  628.        */
  629.  
  630.     } else if (keymatch(arg, "qtables", 2)) {
  631.       /* Quantization tables fetched from file. */
  632.       if (++argn >= argc)    /* advance to next argument */
  633.     usage();
  634.       qtablefile = argv[argn];
  635.       /* We postpone actually reading the file in case -quality comes later. */
  636.  
  637.     } else if (keymatch(arg, "restart", 1)) {
  638.       /* Restart interval in MCU rows (or in MCUs with 'b'). */
  639.       long lval;
  640.       char ch = 'x';
  641.  
  642.       if (++argn >= argc)    /* advance to next argument */
  643.     usage();
  644.       if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
  645.     usage();
  646.       if (lval < 0 || lval > 65535L)
  647.     usage();
  648.       if (ch == 'b' || ch == 'B') {
  649.     cinfo->restart_interval = (unsigned int) lval;
  650.     cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */
  651.       } else {
  652.     cinfo->restart_in_rows = (int) lval;
  653.     /* restart_interval will be computed during startup */
  654.       }
  655.  
  656.     } else if (keymatch(arg, "sample", 2)) {
  657.       /* Set sampling factors. */
  658.       if (++argn >= argc)    /* advance to next argument */
  659.     usage();
  660.       samplearg = argv[argn];
  661.       /* Must delay setting sample factors until after we have processed any
  662.        * colorspace-determining switches, since jpeg_set_colorspace sets
  663.        * default sampling factors.
  664.        */
  665.  
  666.     } else if (keymatch(arg, "smooth", 2)) {
  667.       /* Set input smoothing factor. */
  668.       int val;
  669.  
  670.       if (++argn >= argc)    /* advance to next argument */
  671.     usage();
  672.       if (sscanf(argv[argn], "%d", &val) != 1)
  673.     usage();
  674.       if (val < 0 || val > 100)
  675.     usage();
  676.       cinfo->smoothing_factor = val;
  677.  
  678.     } else if (keymatch(arg, "targa", 1)) {
  679.       /* Input file is Targa format. */
  680.       is_targa = TRUE;
  681.  
  682.     } else {
  683.       usage();            /* bogus switch */
  684.     }
  685.   }
  686.  
  687.   /* Post-switch-scanning cleanup */
  688.  
  689.   if (for_real) {
  690.  
  691.     /* Set quantization tables for selected quality. */
  692.     /* Some or all may be overridden if -qtables is present. */
  693.     jpeg_set_quality(cinfo, quality, force_baseline);
  694.  
  695.     if (qtablefile != NULL)    /* process -qtables if it was present */
  696.       read_quant_tables(cinfo, qtablefile, q_scale_factor, force_baseline);
  697.  
  698.     if (qslotsarg != NULL)    /* process -qslots if it was present */
  699.       set_quant_slots(cinfo, qslotsarg);
  700.  
  701.     if (samplearg != NULL)    /* process -sample if it was present */
  702.       set_sample_factors(cinfo, samplearg);
  703.  
  704.   }
  705.  
  706.   return argn;            /* return index of next arg (file name) */
  707. }
  708.  
  709.  
  710. /*
  711.  * The main program.
  712.  */
  713.  
  714. GLOBAL int
  715. main (int argc, char **argv)
  716. {
  717.   struct jpeg_compress_struct cinfo;
  718.   struct jpeg_error_mgr jerr;
  719. #ifdef PROGRESS_REPORT
  720.   struct cdjpeg_progress_mgr progress;
  721. #endif
  722.   int file_index;
  723. #ifdef OSK
  724.   struct sgbuf obuffer, nbuffer;
  725. #endif
  726.  
  727.   cjpeg_source_ptr src_mgr;
  728.   FILE * input_file;
  729.   FILE * output_file;
  730.   JDIMENSION num_scanlines;
  731.  
  732.   /* On Mac, fetch a command line. */
  733. #ifdef USE_CCOMMAND
  734.   argc = ccommand(&argv);
  735. #endif
  736.  
  737.   progname = argv[0];
  738.   if (progname == NULL || progname[0] == 0)
  739.     progname = "cjpeg";        /* in case C library doesn't provide it */
  740.  
  741.   /* Initialize the JPEG compression object with default error handling. */
  742.   cinfo.err = jpeg_std_error(&jerr);
  743.   jpeg_create_compress(&cinfo);
  744.   /* Add some application-specific error messages (from cderror.h) */
  745.   jerr.addon_message_table = cdjpeg_message_table;
  746.   jerr.first_addon_message = JMSG_FIRSTADDONCODE;
  747.   jerr.last_addon_message = JMSG_LASTADDONCODE;
  748.  
  749.   /* Now safe to enable signal catcher. */
  750. #ifdef NEED_SIGNAL_CATCHER
  751.   sig_cinfo = (j_common_ptr) &cinfo;
  752.   signal(SIGINT, signal_catcher);
  753. #ifdef SIGTERM            /* not all systems have SIGTERM */
  754.   signal(SIGTERM, signal_catcher);
  755. #endif
  756. #endif
  757.  
  758.   /* Initialize JPEG parameters.
  759.    * Much of this may be overridden later.
  760.    * In particular, we don't yet know the input file's color space,
  761.    * but we need to provide some value for jpeg_set_defaults() to work.
  762.    */
  763.  
  764.   cinfo.in_color_space = JCS_RGB; /* arbitrary guess */
  765.   jpeg_set_defaults(&cinfo);
  766.  
  767.   /* Scan command line to find file names.
  768.    * It is convenient to use just one switch-parsing routine, but the switch
  769.    * values read here are ignored; we will rescan the switches after opening
  770.    * the input file.
  771.    */
  772.  
  773.   file_index = parse_switches(&cinfo, argc, argv, 0, FALSE);
  774.  
  775. #ifdef TWO_FILE_COMMANDLINE
  776.   /* Must have either -outfile switch or explicit output file name */
  777.   if (outfilename == NULL) {
  778.     if (file_index != argc-2) {
  779.       fprintf(stderr, "%s: must name one input and one output file\n",
  780.           progname);
  781.       usage();
  782.     }
  783.     outfilename = argv[file_index+1];
  784.   } else {
  785.     if (file_index != argc-1) {
  786.       fprintf(stderr, "%s: must name one input and one output file\n",
  787.           progname);
  788.       usage();
  789.     }
  790.   }
  791. #else
  792.   /* Unix style: expect zero or one file name */
  793.   if (file_index < argc-1) {
  794.     fprintf(stderr, "%s: only one input file\n", progname);
  795.     usage();
  796.   }
  797. #endif /* TWO_FILE_COMMANDLINE */
  798.  
  799.   /* Open the input file. */
  800.   if (file_index < argc) {
  801.     if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
  802.       fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
  803.       exit(EXIT_FAILURE);
  804.     }
  805.   } else {
  806.     /* default input file is stdin */
  807. #ifdef USE_SETMODE        /* need to hack file mode? */
  808.     setmode(fileno(stdin), O_BINARY);
  809. #endif
  810. #ifdef USE_FDOPEN        /* need to re-open in binary mode? */
  811.     if ((input_file = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
  812.       fprintf(stderr, "%s: can't open stdin\n", progname);
  813.       exit(EXIT_FAILURE);
  814.     }
  815. #else
  816.     input_file = stdin;
  817. #endif
  818.   }
  819.  
  820.   /* Open the output file. */
  821.   if (outfilename != NULL) {
  822.     if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
  823.       fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
  824.       exit(EXIT_FAILURE);
  825.     }
  826.   } else {
  827.     /* default output file is stdout */
  828. #ifdef USE_SETMODE        /* need to hack file mode? */
  829.     setmode(fileno(stdout), O_BINARY);
  830. #endif
  831. #ifdef USE_FDOPEN        /* need to re-open in binary mode? */
  832.     if ((output_file = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) {
  833.       fprintf(stderr, "%s: can't open stdout\n", progname);
  834.       exit(EXIT_FAILURE);
  835.     }
  836. #else
  837.     output_file = stdout;
  838. #endif
  839.   }
  840.  
  841. #ifdef PROGRESS_REPORT
  842. #ifdef OSK
  843.   _gs_opt(fileno(stderr), &obuffer);
  844.   nbuffer = obuffer;
  845.   nbuffer.sg_pause = 0;
  846.   nbuffer.sg_alf = 0;
  847.   _ss_opt(fileno(stderr), &nbuffer);
  848. #endif
  849.  
  850.   /* Enable progress display, unless trace output is on */
  851.   if (jerr.trace_level == 0) {
  852.     progress.pub.progress_monitor = progress_monitor;
  853.     progress.completed_extra_passes = 0;
  854.     progress.total_extra_passes = 0;
  855.     progress.percent_done = -1;
  856.     cinfo.progress = &progress.pub;
  857.   }
  858. #endif
  859.  
  860.   /* Figure out the input file format, and set up to read it. */
  861.   src_mgr = select_file_type(&cinfo, input_file);
  862.   src_mgr->input_file = input_file;
  863.  
  864.   /* Read the input file header to obtain file size & colorspace. */
  865.   (*src_mgr->start_input) (&cinfo, src_mgr);
  866.  
  867.   /* Now that we know input colorspace, fix colorspace-dependent defaults */
  868.   jpeg_default_colorspace(&cinfo);
  869.  
  870.   /* Adjust default compression parameters by re-parsing the options */
  871.   file_index = parse_switches(&cinfo, argc, argv, 0, TRUE);
  872.  
  873.   /* Specify data destination for compression */
  874.   jpeg_stdio_dest(&cinfo, output_file);
  875.  
  876.   /* Start compressor */
  877.   jpeg_start_compress(&cinfo, TRUE);
  878.  
  879.   /* Process data */
  880.   while (cinfo.next_scanline < cinfo.image_height) {
  881.     num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr);
  882.     (void) jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines);
  883.   }
  884.  
  885.   /* Finish compression and release memory */
  886.   (*src_mgr->finish_input) (&cinfo, src_mgr);
  887.   jpeg_finish_compress(&cinfo);
  888.   jpeg_destroy_compress(&cinfo);
  889.  
  890.   /* Close files, if we opened them */
  891.   if (input_file != stdin)
  892.     fclose(input_file);
  893.   if (output_file != stdout)
  894.     fclose(output_file);
  895.  
  896. #ifdef PROGRESS_REPORT
  897. #ifdef OSK
  898.   _ss_opt(fileno(stderr), &obuffer);
  899. #endif
  900.  
  901.   /* Clear away progress display */
  902.   if (jerr.trace_level == 0) {
  903.     fprintf(stderr, "\r                \r");
  904.     fflush(stderr);
  905.   }
  906. #endif
  907.  
  908.   /* All done. */
  909.   exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);
  910.   return 0;            /* suppress no-return-value warnings */
  911. }
  912.