blob: 6fe7ee1888eb790fc24b10a1778dfffca8a6f8d4 [file] [log] [blame]
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +00001/*
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 */
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +000027#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
Thomas G. Lane9ba2f5e1994-12-07 00:00:00 +000075/* Create the add-on message string table. */
76
77#define JMESSAGE(code,string) string ,
78
79static const char * const cdjpeg_message_table[] = {
80#include "cderror.h"
81 NULL
82};
83
84
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +000085/*
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
111static boolean is_targa; /* records user -targa switch */
112
113
114LOCAL cjpeg_source_ptr
115select_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
170static j_common_ptr sig_cinfo;
171
172GLOBAL void
173signal_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
192METHODDEF void
193progress_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
224static const char * progname; /* program name for error messages */
225static char * outfilename; /* for -outfile switch */
226
227
228LOCAL void
229usage (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
283LOCAL boolean
284keymatch (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
308LOCAL int
309qt_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
325LOCAL long
326read_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
354LOCAL void
355read_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
411LOCAL void
412set_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
445LOCAL void
446set_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
479LOCAL int
480parse_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
710GLOBAL int
711main (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) */
Thomas G. Lane9ba2f5e1994-12-07 00:00:00 +0000737 jerr.addon_message_table = cdjpeg_message_table;
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000738 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
Thomas G. Lane9ba2f5e1994-12-07 00:00:00 +0000874 /* 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
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000880#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}