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