source: trunk/third/firefox/jpeg/cjpeg.c @ 21695

Revision 21695, 19.4 KB checked in by rbasch, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21694, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * cjpeg.c
3 *
4 * Copyright (C) 1991-1998, 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 USE_CCOMMAND             /* command-line reader for Macintosh */
30#ifdef __MWERKS__
31#include <SIOUX.h>              /* Metrowerks needs this */
32#include <console.h>            /* ... and this */
33#endif
34#ifdef THINK_C
35#include <console.h>            /* Think declares it here */
36#endif
37#endif
38
39
40/* Create the add-on message string table. */
41
42#define JMESSAGE(code,string)   string ,
43
44static const char * const cdjpeg_message_table[] = {
45#include "cderror.h"
46  NULL
47};
48
49
50/*
51 * This routine determines what format the input file is,
52 * and selects the appropriate input-reading module.
53 *
54 * To determine which family of input formats the file belongs to,
55 * we may look only at the first byte of the file, since C does not
56 * guarantee that more than one character can be pushed back with ungetc.
57 * Looking at additional bytes would require one of these approaches:
58 *     1) assume we can fseek() the input file (fails for piped input);
59 *     2) assume we can push back more than one character (works in
60 *        some C implementations, but unportable);
61 *     3) provide our own buffering (breaks input readers that want to use
62 *        stdio directly, such as the RLE library);
63 * or  4) don't put back the data, and modify the input_init methods to assume
64 *        they start reading after the start of file (also breaks RLE library).
65 * #1 is attractive for MS-DOS but is untenable on Unix.
66 *
67 * The most portable solution for file types that can't be identified by their
68 * first byte is to make the user tell us what they are.  This is also the
69 * only approach for "raw" file types that contain only arbitrary values.
70 * We presently apply this method for Targa files.  Most of the time Targa
71 * files start with 0x00, so we recognize that case.  Potentially, however,
72 * a Targa file could start with any byte value (byte 0 is the length of the
73 * seldom-used ID field), so we provide a switch to force Targa input mode.
74 */
75
76static boolean is_targa;        /* records user -targa switch */
77
78
79LOCAL(cjpeg_source_ptr)
80select_file_type (j_compress_ptr cinfo, FILE * infile)
81{
82  int c;
83
84  if (is_targa) {
85#ifdef TARGA_SUPPORTED
86    return jinit_read_targa(cinfo);
87#else
88    ERREXIT(cinfo, JERR_TGA_NOTCOMP);
89#endif
90  }
91
92  if ((c = getc(infile)) == EOF)
93    ERREXIT(cinfo, JERR_INPUT_EMPTY);
94  if (ungetc(c, infile) == EOF)
95    ERREXIT(cinfo, JERR_UNGETC_FAILED);
96
97  switch (c) {
98#ifdef BMP_SUPPORTED
99  case 'B':
100    return jinit_read_bmp(cinfo);
101#endif
102#ifdef GIF_SUPPORTED
103  case 'G':
104    return jinit_read_gif(cinfo);
105#endif
106#ifdef PPM_SUPPORTED
107  case 'P':
108    return jinit_read_ppm(cinfo);
109#endif
110#ifdef RLE_SUPPORTED
111  case 'R':
112    return jinit_read_rle(cinfo);
113#endif
114#ifdef TARGA_SUPPORTED
115  case 0x00:
116    return jinit_read_targa(cinfo);
117#endif
118  default:
119    ERREXIT(cinfo, JERR_UNKNOWN_FORMAT);
120    break;
121  }
122
123  return NULL;                  /* suppress compiler warnings */
124}
125
126
127/*
128 * Argument-parsing code.
129 * The switch parser is designed to be useful with DOS-style command line
130 * syntax, ie, intermixed switches and file names, where only the switches
131 * to the left of a given file name affect processing of that file.
132 * The main program in this file doesn't actually use this capability...
133 */
134
135
136static const char * progname;   /* program name for error messages */
137static char * outfilename;      /* for -outfile switch */
138
139
140LOCAL(void)
141usage (void)
142/* complain about bad command line */
143{
144  fprintf(stderr, "usage: %s [switches] ", progname);
145#ifdef TWO_FILE_COMMANDLINE
146  fprintf(stderr, "inputfile outputfile\n");
147#else
148  fprintf(stderr, "[inputfile]\n");
149#endif
150
151  fprintf(stderr, "Switches (names may be abbreviated):\n");
152  fprintf(stderr, "  -quality N     Compression quality (0..100; 5-95 is useful range)\n");
153  fprintf(stderr, "  -grayscale     Create monochrome JPEG file\n");
154#ifdef ENTROPY_OPT_SUPPORTED
155  fprintf(stderr, "  -optimize      Optimize Huffman table (smaller file, but slow compression)\n");
156#endif
157#ifdef C_PROGRESSIVE_SUPPORTED
158  fprintf(stderr, "  -progressive   Create progressive JPEG file\n");
159#endif
160#ifdef TARGA_SUPPORTED
161  fprintf(stderr, "  -targa         Input file is Targa format (usually not needed)\n");
162#endif
163  fprintf(stderr, "Switches for advanced users:\n");
164#ifdef DCT_ISLOW_SUPPORTED
165  fprintf(stderr, "  -dct int       Use integer DCT method%s\n",
166          (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : ""));
167#endif
168#ifdef DCT_IFAST_SUPPORTED
169  fprintf(stderr, "  -dct fast      Use fast integer DCT (less accurate)%s\n",
170          (JDCT_DEFAULT == JDCT_IFAST ? " (default)" : ""));
171#endif
172#ifdef DCT_FLOAT_SUPPORTED
173  fprintf(stderr, "  -dct float     Use floating-point DCT method%s\n",
174          (JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : ""));
175#endif
176  fprintf(stderr, "  -restart N     Set restart interval in rows, or in blocks with B\n");
177#ifdef INPUT_SMOOTHING_SUPPORTED
178  fprintf(stderr, "  -smooth N      Smooth dithered input (N=1..100 is strength)\n");
179#endif
180  fprintf(stderr, "  -maxmemory N   Maximum memory to use (in kbytes)\n");
181  fprintf(stderr, "  -outfile name  Specify name for output file\n");
182  fprintf(stderr, "  -verbose  or  -debug   Emit debug output\n");
183  fprintf(stderr, "Switches for wizards:\n");
184#ifdef C_ARITH_CODING_SUPPORTED
185  fprintf(stderr, "  -arithmetic    Use arithmetic coding\n");
186#endif
187  fprintf(stderr, "  -baseline      Force baseline quantization tables\n");
188  fprintf(stderr, "  -qtables file  Use quantization tables given in file\n");
189  fprintf(stderr, "  -qslots N[,...]    Set component quantization tables\n");
190  fprintf(stderr, "  -sample HxV[,...]  Set component sampling factors\n");
191#ifdef C_MULTISCAN_FILES_SUPPORTED
192  fprintf(stderr, "  -scans file    Create multi-scan JPEG per script file\n");
193#endif
194  exit(EXIT_FAILURE);
195}
196
197
198LOCAL(int)
199parse_switches (j_compress_ptr cinfo, int argc, char **argv,
200                int last_file_arg_seen, boolean for_real)
201/* Parse optional switches.
202 * Returns argv[] index of first file-name argument (== argc if none).
203 * Any file names with indexes <= last_file_arg_seen are ignored;
204 * they have presumably been processed in a previous iteration.
205 * (Pass 0 for last_file_arg_seen on the first or only iteration.)
206 * for_real is FALSE on the first (dummy) pass; we may skip any expensive
207 * processing.
208 */
209{
210  int argn;
211  char * arg;
212  int quality;                  /* -quality parameter */
213  int q_scale_factor;           /* scaling percentage for -qtables */
214  boolean force_baseline;
215  boolean simple_progressive;
216  char * qtablefile = NULL;     /* saves -qtables filename if any */
217  char * qslotsarg = NULL;      /* saves -qslots parm if any */
218  char * samplearg = NULL;      /* saves -sample parm if any */
219  char * scansarg = NULL;       /* saves -scans parm if any */
220
221  /* Set up default JPEG parameters. */
222  /* Note that default -quality level need not, and does not,
223   * match the default scaling for an explicit -qtables argument.
224   */
225  quality = 75;                 /* default -quality value */
226  q_scale_factor = 100;         /* default to no scaling for -qtables */
227  force_baseline = FALSE;       /* by default, allow 16-bit quantizers */
228  simple_progressive = FALSE;
229  is_targa = FALSE;
230  outfilename = NULL;
231  cinfo->err->trace_level = 0;
232
233  /* Scan command line options, adjust parameters */
234
235  for (argn = 1; argn < argc; argn++) {
236    arg = argv[argn];
237    if (*arg != '-') {
238      /* Not a switch, must be a file name argument */
239      if (argn <= last_file_arg_seen) {
240        outfilename = NULL;     /* -outfile applies to just one input file */
241        continue;               /* ignore this name if previously processed */
242      }
243      break;                    /* else done parsing switches */
244    }
245    arg++;                      /* advance past switch marker character */
246
247    if (keymatch(arg, "arithmetic", 1)) {
248      /* Use arithmetic coding. */
249#ifdef C_ARITH_CODING_SUPPORTED
250      cinfo->arith_code = TRUE;
251#else
252      fprintf(stderr, "%s: sorry, arithmetic coding not supported\n",
253              progname);
254      exit(EXIT_FAILURE);
255#endif
256
257    } else if (keymatch(arg, "baseline", 1)) {
258      /* Force baseline-compatible output (8-bit quantizer values). */
259      force_baseline = TRUE;
260
261    } else if (keymatch(arg, "dct", 2)) {
262      /* Select DCT algorithm. */
263      if (++argn >= argc)       /* advance to next argument */
264        usage();
265      if (keymatch(argv[argn], "int", 1)) {
266        cinfo->dct_method = JDCT_ISLOW;
267      } else if (keymatch(argv[argn], "fast", 2)) {
268        cinfo->dct_method = JDCT_IFAST;
269      } else if (keymatch(argv[argn], "float", 2)) {
270        cinfo->dct_method = JDCT_FLOAT;
271      } else
272        usage();
273
274    } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
275      /* Enable debug printouts. */
276      /* On first -d, print version identification */
277      static boolean printed_version = FALSE;
278
279      if (! printed_version) {
280        fprintf(stderr, "Independent JPEG Group's CJPEG, version %s\n%s\n",
281                JVERSION, JCOPYRIGHT);
282        printed_version = TRUE;
283      }
284      cinfo->err->trace_level++;
285
286    } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) {
287      /* Force a monochrome JPEG file to be generated. */
288      jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
289
290    } else if (keymatch(arg, "maxmemory", 3)) {
291      /* Maximum memory in Kb (or Mb with 'm'). */
292      long lval;
293      char ch = 'x';
294
295      if (++argn >= argc)       /* advance to next argument */
296        usage();
297      if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
298        usage();
299      if (ch == 'm' || ch == 'M')
300        lval *= 1000L;
301      cinfo->mem->max_memory_to_use = lval * 1000L;
302
303    } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) {
304      /* Enable entropy parm optimization. */
305#ifdef ENTROPY_OPT_SUPPORTED
306      cinfo->optimize_coding = TRUE;
307#else
308      fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n",
309              progname);
310      exit(EXIT_FAILURE);
311#endif
312
313    } else if (keymatch(arg, "outfile", 4)) {
314      /* Set output file name. */
315      if (++argn >= argc)       /* advance to next argument */
316        usage();
317      outfilename = argv[argn]; /* save it away for later use */
318
319    } else if (keymatch(arg, "progressive", 1)) {
320      /* Select simple progressive mode. */
321#ifdef C_PROGRESSIVE_SUPPORTED
322      simple_progressive = TRUE;
323      /* We must postpone execution until num_components is known. */
324#else
325      fprintf(stderr, "%s: sorry, progressive output was not compiled\n",
326              progname);
327      exit(EXIT_FAILURE);
328#endif
329
330    } else if (keymatch(arg, "quality", 1)) {
331      /* Quality factor (quantization table scaling factor). */
332      if (++argn >= argc)       /* advance to next argument */
333        usage();
334      if (sscanf(argv[argn], "%d", &quality) != 1)
335        usage();
336      /* Change scale factor in case -qtables is present. */
337      q_scale_factor = jpeg_quality_scaling(quality);
338
339    } else if (keymatch(arg, "qslots", 2)) {
340      /* Quantization table slot numbers. */
341      if (++argn >= argc)       /* advance to next argument */
342        usage();
343      qslotsarg = argv[argn];
344      /* Must delay setting qslots until after we have processed any
345       * colorspace-determining switches, since jpeg_set_colorspace sets
346       * default quant table numbers.
347       */
348
349    } else if (keymatch(arg, "qtables", 2)) {
350      /* Quantization tables fetched from file. */
351      if (++argn >= argc)       /* advance to next argument */
352        usage();
353      qtablefile = argv[argn];
354      /* We postpone actually reading the file in case -quality comes later. */
355
356    } else if (keymatch(arg, "restart", 1)) {
357      /* Restart interval in MCU rows (or in MCUs with 'b'). */
358      long lval;
359      char ch = 'x';
360
361      if (++argn >= argc)       /* advance to next argument */
362        usage();
363      if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
364        usage();
365      if (lval < 0 || lval > 65535L)
366        usage();
367      if (ch == 'b' || ch == 'B') {
368        cinfo->restart_interval = (unsigned int) lval;
369        cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */
370      } else {
371        cinfo->restart_in_rows = (int) lval;
372        /* restart_interval will be computed during startup */
373      }
374
375    } else if (keymatch(arg, "sample", 2)) {
376      /* Set sampling factors. */
377      if (++argn >= argc)       /* advance to next argument */
378        usage();
379      samplearg = argv[argn];
380      /* Must delay setting sample factors until after we have processed any
381       * colorspace-determining switches, since jpeg_set_colorspace sets
382       * default sampling factors.
383       */
384
385    } else if (keymatch(arg, "scans", 2)) {
386      /* Set scan script. */
387#ifdef C_MULTISCAN_FILES_SUPPORTED
388      if (++argn >= argc)       /* advance to next argument */
389        usage();
390      scansarg = argv[argn];
391      /* We must postpone reading the file in case -progressive appears. */
392#else
393      fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n",
394              progname);
395      exit(EXIT_FAILURE);
396#endif
397
398    } else if (keymatch(arg, "smooth", 2)) {
399      /* Set input smoothing factor. */
400      int val;
401
402      if (++argn >= argc)       /* advance to next argument */
403        usage();
404      if (sscanf(argv[argn], "%d", &val) != 1)
405        usage();
406      if (val < 0 || val > 100)
407        usage();
408      cinfo->smoothing_factor = val;
409
410    } else if (keymatch(arg, "targa", 1)) {
411      /* Input file is Targa format. */
412      is_targa = TRUE;
413
414    } else {
415      usage();                  /* bogus switch */
416    }
417  }
418
419  /* Post-switch-scanning cleanup */
420
421  if (for_real) {
422
423    /* Set quantization tables for selected quality. */
424    /* Some or all may be overridden if -qtables is present. */
425    jpeg_set_quality(cinfo, quality, force_baseline);
426
427    if (qtablefile != NULL)     /* process -qtables if it was present */
428      if (! read_quant_tables(cinfo, qtablefile,
429                              q_scale_factor, force_baseline))
430        usage();
431
432    if (qslotsarg != NULL)      /* process -qslots if it was present */
433      if (! set_quant_slots(cinfo, qslotsarg))
434        usage();
435
436    if (samplearg != NULL)      /* process -sample if it was present */
437      if (! set_sample_factors(cinfo, samplearg))
438        usage();
439
440#ifdef C_PROGRESSIVE_SUPPORTED
441    if (simple_progressive)     /* process -progressive; -scans can override */
442      jpeg_simple_progression(cinfo);
443#endif
444
445#ifdef C_MULTISCAN_FILES_SUPPORTED
446    if (scansarg != NULL)       /* process -scans if it was present */
447      if (! read_scan_script(cinfo, scansarg))
448        usage();
449#endif
450  }
451
452  return argn;                  /* return index of next arg (file name) */
453}
454
455
456/*
457 * The main program.
458 */
459
460int
461main (int argc, char **argv)
462{
463  struct jpeg_compress_struct cinfo;
464  struct jpeg_error_mgr jerr;
465#ifdef PROGRESS_REPORT
466  struct cdjpeg_progress_mgr progress;
467#endif
468  int file_index;
469  cjpeg_source_ptr src_mgr;
470  FILE * input_file;
471  FILE * output_file;
472  JDIMENSION num_scanlines;
473
474  /* On Mac, fetch a command line. */
475#ifdef USE_CCOMMAND
476  argc = ccommand(&argv);
477#endif
478
479  progname = argv[0];
480  if (progname == NULL || progname[0] == 0)
481    progname = "cjpeg";         /* in case C library doesn't provide it */
482
483  /* Initialize the JPEG compression object with default error handling. */
484  cinfo.err = jpeg_std_error(&jerr);
485  jpeg_create_compress(&cinfo);
486  /* Add some application-specific error messages (from cderror.h) */
487  jerr.addon_message_table = cdjpeg_message_table;
488  jerr.first_addon_message = JMSG_FIRSTADDONCODE;
489  jerr.last_addon_message = JMSG_LASTADDONCODE;
490
491  /* Now safe to enable signal catcher. */
492#ifdef NEED_SIGNAL_CATCHER
493  enable_signal_catcher((j_common_ptr) &cinfo);
494#endif
495
496  /* Initialize JPEG parameters.
497   * Much of this may be overridden later.
498   * In particular, we don't yet know the input file's color space,
499   * but we need to provide some value for jpeg_set_defaults() to work.
500   */
501
502  cinfo.in_color_space = JCS_RGB; /* arbitrary guess */
503  jpeg_set_defaults(&cinfo);
504
505  /* Scan command line to find file names.
506   * It is convenient to use just one switch-parsing routine, but the switch
507   * values read here are ignored; we will rescan the switches after opening
508   * the input file.
509   */
510
511  file_index = parse_switches(&cinfo, argc, argv, 0, FALSE);
512
513#ifdef TWO_FILE_COMMANDLINE
514  /* Must have either -outfile switch or explicit output file name */
515  if (outfilename == NULL) {
516    if (file_index != argc-2) {
517      fprintf(stderr, "%s: must name one input and one output file\n",
518              progname);
519      usage();
520    }
521    outfilename = argv[file_index+1];
522  } else {
523    if (file_index != argc-1) {
524      fprintf(stderr, "%s: must name one input and one output file\n",
525              progname);
526      usage();
527    }
528  }
529#else
530  /* Unix style: expect zero or one file name */
531  if (file_index < argc-1) {
532    fprintf(stderr, "%s: only one input file\n", progname);
533    usage();
534  }
535#endif /* TWO_FILE_COMMANDLINE */
536
537  /* Open the input file. */
538  if (file_index < argc) {
539    if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
540      fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
541      exit(EXIT_FAILURE);
542    }
543  } else {
544    /* default input file is stdin */
545    input_file = read_stdin();
546  }
547
548  /* Open the output file. */
549  if (outfilename != NULL) {
550    if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
551      fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
552      exit(EXIT_FAILURE);
553    }
554  } else {
555    /* default output file is stdout */
556    output_file = write_stdout();
557  }
558
559#ifdef PROGRESS_REPORT
560  start_progress_monitor((j_common_ptr) &cinfo, &progress);
561#endif
562
563  /* Figure out the input file format, and set up to read it. */
564  src_mgr = select_file_type(&cinfo, input_file);
565  src_mgr->input_file = input_file;
566
567  /* Read the input file header to obtain file size & colorspace. */
568  (*src_mgr->start_input) (&cinfo, src_mgr);
569
570  /* Now that we know input colorspace, fix colorspace-dependent defaults */
571  jpeg_default_colorspace(&cinfo);
572
573  /* Adjust default compression parameters by re-parsing the options */
574  file_index = parse_switches(&cinfo, argc, argv, 0, TRUE);
575
576  /* Specify data destination for compression */
577  jpeg_stdio_dest(&cinfo, output_file);
578
579  /* Start compressor */
580  jpeg_start_compress(&cinfo, TRUE);
581
582  /* Process data */
583  while (cinfo.next_scanline < cinfo.image_height) {
584    num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr);
585    (void) jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines);
586  }
587
588  /* Finish compression and release memory */
589  (*src_mgr->finish_input) (&cinfo, src_mgr);
590  jpeg_finish_compress(&cinfo);
591  jpeg_destroy_compress(&cinfo);
592
593  /* Close files, if we opened them */
594  if (input_file != stdin)
595    fclose(input_file);
596  if (output_file != stdout)
597    fclose(output_file);
598
599#ifdef PROGRESS_REPORT
600  end_progress_monitor((j_common_ptr) &cinfo);
601#endif
602
603  /* All done. */
604  exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);
605  return 0;                     /* suppress no-return-value warnings */
606}
Note: See TracBrowser for help on using the repository browser.