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

Revision 21695, 18.9 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 * djpeg.c
3 *
4 * Copyright (C) 1991-1997, 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 decompressor.
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 *      djpeg [options]  inputfile outputfile
14 *      djpeg [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 *      djpeg [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 isprint() */
30
31#ifdef USE_CCOMMAND             /* command-line reader for Macintosh */
32#ifdef __MWERKS__
33#include <SIOUX.h>              /* Metrowerks needs this */
34#include <console.h>            /* ... and this */
35#endif
36#ifdef THINK_C
37#include <console.h>            /* Think declares it here */
38#endif
39#endif
40
41
42/* Create the add-on message string table. */
43
44#define JMESSAGE(code,string)   string ,
45
46static const char * const cdjpeg_message_table[] = {
47#include "cderror.h"
48  NULL
49};
50
51
52/*
53 * This list defines the known output image formats
54 * (not all of which need be supported by a given version).
55 * You can change the default output format by defining DEFAULT_FMT;
56 * indeed, you had better do so if you undefine PPM_SUPPORTED.
57 */
58
59typedef enum {
60        FMT_BMP,                /* BMP format (Windows flavor) */
61        FMT_GIF,                /* GIF format */
62        FMT_OS2,                /* BMP format (OS/2 flavor) */
63        FMT_PPM,                /* PPM/PGM (PBMPLUS formats) */
64        FMT_RLE,                /* RLE format */
65        FMT_TARGA,              /* Targa format */
66        FMT_TIFF                /* TIFF format */
67} IMAGE_FORMATS;
68
69#ifndef DEFAULT_FMT             /* so can override from CFLAGS in Makefile */
70#define DEFAULT_FMT     FMT_PPM
71#endif
72
73static IMAGE_FORMATS requested_fmt;
74
75
76/*
77 * Argument-parsing code.
78 * The switch parser is designed to be useful with DOS-style command line
79 * syntax, ie, intermixed switches and file names, where only the switches
80 * to the left of a given file name affect processing of that file.
81 * The main program in this file doesn't actually use this capability...
82 */
83
84
85static const char * progname;   /* program name for error messages */
86static char * outfilename;      /* for -outfile switch */
87
88
89LOCAL(void)
90usage (void)
91/* complain about bad command line */
92{
93  fprintf(stderr, "usage: %s [switches] ", progname);
94#ifdef TWO_FILE_COMMANDLINE
95  fprintf(stderr, "inputfile outputfile\n");
96#else
97  fprintf(stderr, "[inputfile]\n");
98#endif
99
100  fprintf(stderr, "Switches (names may be abbreviated):\n");
101  fprintf(stderr, "  -colors N      Reduce image to no more than N colors\n");
102  fprintf(stderr, "  -fast          Fast, low-quality processing\n");
103  fprintf(stderr, "  -grayscale     Force grayscale output\n");
104#ifdef IDCT_SCALING_SUPPORTED
105  fprintf(stderr, "  -scale M/N     Scale output image by fraction M/N, eg, 1/8\n");
106#endif
107#ifdef BMP_SUPPORTED
108  fprintf(stderr, "  -bmp           Select BMP output format (Windows style)%s\n",
109          (DEFAULT_FMT == FMT_BMP ? " (default)" : ""));
110#endif
111#ifdef GIF_SUPPORTED
112  fprintf(stderr, "  -gif           Select GIF output format%s\n",
113          (DEFAULT_FMT == FMT_GIF ? " (default)" : ""));
114#endif
115#ifdef BMP_SUPPORTED
116  fprintf(stderr, "  -os2           Select BMP output format (OS/2 style)%s\n",
117          (DEFAULT_FMT == FMT_OS2 ? " (default)" : ""));
118#endif
119#ifdef PPM_SUPPORTED
120  fprintf(stderr, "  -pnm           Select PBMPLUS (PPM/PGM) output format%s\n",
121          (DEFAULT_FMT == FMT_PPM ? " (default)" : ""));
122#endif
123#ifdef RLE_SUPPORTED
124  fprintf(stderr, "  -rle           Select Utah RLE output format%s\n",
125          (DEFAULT_FMT == FMT_RLE ? " (default)" : ""));
126#endif
127#ifdef TARGA_SUPPORTED
128  fprintf(stderr, "  -targa         Select Targa output format%s\n",
129          (DEFAULT_FMT == FMT_TARGA ? " (default)" : ""));
130#endif
131  fprintf(stderr, "Switches for advanced users:\n");
132#ifdef DCT_ISLOW_SUPPORTED
133  fprintf(stderr, "  -dct int       Use integer DCT method%s\n",
134          (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : ""));
135#endif
136#ifdef DCT_IFAST_SUPPORTED
137  fprintf(stderr, "  -dct fast      Use fast integer DCT (less accurate)%s\n",
138          (JDCT_DEFAULT == JDCT_IFAST ? " (default)" : ""));
139#endif
140#ifdef DCT_FLOAT_SUPPORTED
141  fprintf(stderr, "  -dct float     Use floating-point DCT method%s\n",
142          (JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : ""));
143#endif
144  fprintf(stderr, "  -dither fs     Use F-S dithering (default)\n");
145  fprintf(stderr, "  -dither none   Don't use dithering in quantization\n");
146  fprintf(stderr, "  -dither ordered  Use ordered dither (medium speed, quality)\n");
147#ifdef QUANT_2PASS_SUPPORTED
148  fprintf(stderr, "  -map FILE      Map to colors used in named image file\n");
149#endif
150  fprintf(stderr, "  -nosmooth      Don't use high-quality upsampling\n");
151#ifdef QUANT_1PASS_SUPPORTED
152  fprintf(stderr, "  -onepass       Use 1-pass quantization (fast, low quality)\n");
153#endif
154  fprintf(stderr, "  -maxmemory N   Maximum memory to use (in kbytes)\n");
155  fprintf(stderr, "  -outfile name  Specify name for output file\n");
156  fprintf(stderr, "  -verbose  or  -debug   Emit debug output\n");
157  exit(EXIT_FAILURE);
158}
159
160
161LOCAL(int)
162parse_switches (j_decompress_ptr cinfo, int argc, char **argv,
163                int last_file_arg_seen, boolean for_real)
164/* Parse optional switches.
165 * Returns argv[] index of first file-name argument (== argc if none).
166 * Any file names with indexes <= last_file_arg_seen are ignored;
167 * they have presumably been processed in a previous iteration.
168 * (Pass 0 for last_file_arg_seen on the first or only iteration.)
169 * for_real is FALSE on the first (dummy) pass; we may skip any expensive
170 * processing.
171 */
172{
173  int argn;
174  char * arg;
175
176  /* Set up default JPEG parameters. */
177  requested_fmt = DEFAULT_FMT;  /* set default output file format */
178  outfilename = NULL;
179  cinfo->err->trace_level = 0;
180
181  /* Scan command line options, adjust parameters */
182
183  for (argn = 1; argn < argc; argn++) {
184    arg = argv[argn];
185    if (*arg != '-') {
186      /* Not a switch, must be a file name argument */
187      if (argn <= last_file_arg_seen) {
188        outfilename = NULL;     /* -outfile applies to just one input file */
189        continue;               /* ignore this name if previously processed */
190      }
191      break;                    /* else done parsing switches */
192    }
193    arg++;                      /* advance past switch marker character */
194
195    if (keymatch(arg, "bmp", 1)) {
196      /* BMP output format. */
197      requested_fmt = FMT_BMP;
198
199    } else if (keymatch(arg, "colors", 1) || keymatch(arg, "colours", 1) ||
200               keymatch(arg, "quantize", 1) || keymatch(arg, "quantise", 1)) {
201      /* Do color quantization. */
202      int val;
203
204      if (++argn >= argc)       /* advance to next argument */
205        usage();
206      if (sscanf(argv[argn], "%d", &val) != 1)
207        usage();
208      cinfo->desired_number_of_colors = val;
209      cinfo->quantize_colors = TRUE;
210
211    } else if (keymatch(arg, "dct", 2)) {
212      /* Select IDCT algorithm. */
213      if (++argn >= argc)       /* advance to next argument */
214        usage();
215      if (keymatch(argv[argn], "int", 1)) {
216        cinfo->dct_method = JDCT_ISLOW;
217      } else if (keymatch(argv[argn], "fast", 2)) {
218        cinfo->dct_method = JDCT_IFAST;
219      } else if (keymatch(argv[argn], "float", 2)) {
220        cinfo->dct_method = JDCT_FLOAT;
221      } else
222        usage();
223
224    } else if (keymatch(arg, "dither", 2)) {
225      /* Select dithering algorithm. */
226      if (++argn >= argc)       /* advance to next argument */
227        usage();
228      if (keymatch(argv[argn], "fs", 2)) {
229        cinfo->dither_mode = JDITHER_FS;
230      } else if (keymatch(argv[argn], "none", 2)) {
231        cinfo->dither_mode = JDITHER_NONE;
232      } else if (keymatch(argv[argn], "ordered", 2)) {
233        cinfo->dither_mode = JDITHER_ORDERED;
234      } else
235        usage();
236
237    } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
238      /* Enable debug printouts. */
239      /* On first -d, print version identification */
240      static boolean printed_version = FALSE;
241
242      if (! printed_version) {
243        fprintf(stderr, "Independent JPEG Group's DJPEG, version %s\n%s\n",
244                JVERSION, JCOPYRIGHT);
245        printed_version = TRUE;
246      }
247      cinfo->err->trace_level++;
248
249    } else if (keymatch(arg, "fast", 1)) {
250      /* Select recommended processing options for quick-and-dirty output. */
251      cinfo->two_pass_quantize = FALSE;
252      cinfo->dither_mode = JDITHER_ORDERED;
253      if (! cinfo->quantize_colors) /* don't override an earlier -colors */
254        cinfo->desired_number_of_colors = 216;
255      cinfo->dct_method = JDCT_FASTEST;
256      cinfo->do_fancy_upsampling = FALSE;
257
258    } else if (keymatch(arg, "gif", 1)) {
259      /* GIF output format. */
260      requested_fmt = FMT_GIF;
261
262    } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) {
263      /* Force monochrome output. */
264      cinfo->out_color_space = JCS_GRAYSCALE;
265
266    } else if (keymatch(arg, "map", 3)) {
267      /* Quantize to a color map taken from an input file. */
268      if (++argn >= argc)       /* advance to next argument */
269        usage();
270      if (for_real) {           /* too expensive to do twice! */
271#ifdef QUANT_2PASS_SUPPORTED    /* otherwise can't quantize to supplied map */
272        FILE * mapfile;
273
274        if ((mapfile = fopen(argv[argn], READ_BINARY)) == NULL) {
275          fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
276          exit(EXIT_FAILURE);
277        }
278        read_color_map(cinfo, mapfile);
279        fclose(mapfile);
280        cinfo->quantize_colors = TRUE;
281#else
282        ERREXIT(cinfo, JERR_NOT_COMPILED);
283#endif
284      }
285
286    } else if (keymatch(arg, "maxmemory", 3)) {
287      /* Maximum memory in Kb (or Mb with 'm'). */
288      long lval;
289      char ch = 'x';
290
291      if (++argn >= argc)       /* advance to next argument */
292        usage();
293      if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
294        usage();
295      if (ch == 'm' || ch == 'M')
296        lval *= 1000L;
297      cinfo->mem->max_memory_to_use = lval * 1000L;
298
299    } else if (keymatch(arg, "nosmooth", 3)) {
300      /* Suppress fancy upsampling */
301      cinfo->do_fancy_upsampling = FALSE;
302
303    } else if (keymatch(arg, "onepass", 3)) {
304      /* Use fast one-pass quantization. */
305      cinfo->two_pass_quantize = FALSE;
306
307    } else if (keymatch(arg, "os2", 3)) {
308      /* BMP output format (OS/2 flavor). */
309      requested_fmt = FMT_OS2;
310
311    } else if (keymatch(arg, "outfile", 4)) {
312      /* Set output file name. */
313      if (++argn >= argc)       /* advance to next argument */
314        usage();
315      outfilename = argv[argn]; /* save it away for later use */
316
317    } else if (keymatch(arg, "pnm", 1) || keymatch(arg, "ppm", 1)) {
318      /* PPM/PGM output format. */
319      requested_fmt = FMT_PPM;
320
321    } else if (keymatch(arg, "rle", 1)) {
322      /* RLE output format. */
323      requested_fmt = FMT_RLE;
324
325    } else if (keymatch(arg, "scale", 1)) {
326      /* Scale the output image by a fraction M/N. */
327      if (++argn >= argc)       /* advance to next argument */
328        usage();
329      if (sscanf(argv[argn], "%d/%d",
330                 &cinfo->scale_num, &cinfo->scale_denom) != 2)
331        usage();
332
333    } else if (keymatch(arg, "targa", 1)) {
334      /* Targa output format. */
335      requested_fmt = FMT_TARGA;
336
337    } else {
338      usage();                  /* bogus switch */
339    }
340  }
341
342  return argn;                  /* return index of next arg (file name) */
343}
344
345
346/*
347 * Marker processor for COM and interesting APPn markers.
348 * This replaces the library's built-in processor, which just skips the marker.
349 * We want to print out the marker as text, to the extent possible.
350 * Note this code relies on a non-suspending data source.
351 */
352
353LOCAL(unsigned int)
354jpeg_getc (j_decompress_ptr cinfo)
355/* Read next byte */
356{
357  struct jpeg_source_mgr * datasrc = cinfo->src;
358
359  if (datasrc->bytes_in_buffer == 0) {
360    if (! (*datasrc->fill_input_buffer) (cinfo))
361      ERREXIT(cinfo, JERR_CANT_SUSPEND);
362  }
363  datasrc->bytes_in_buffer--;
364  return GETJOCTET(*datasrc->next_input_byte++);
365}
366
367
368METHODDEF(boolean)
369print_text_marker (j_decompress_ptr cinfo)
370{
371  boolean traceit = (cinfo->err->trace_level >= 1);
372  INT32 length;
373  unsigned int ch;
374  unsigned int lastch = 0;
375
376  length = jpeg_getc(cinfo) << 8;
377  length += jpeg_getc(cinfo);
378  length -= 2;                  /* discount the length word itself */
379
380  if (traceit) {
381    if (cinfo->unread_marker == JPEG_COM)
382      fprintf(stderr, "Comment, length %ld:\n", (long) length);
383    else                        /* assume it is an APPn otherwise */
384      fprintf(stderr, "APP%d, length %ld:\n",
385              cinfo->unread_marker - JPEG_APP0, (long) length);
386  }
387
388  while (--length >= 0) {
389    ch = jpeg_getc(cinfo);
390    if (traceit) {
391      /* Emit the character in a readable form.
392       * Nonprintables are converted to \nnn form,
393       * while \ is converted to \\.
394       * Newlines in CR, CR/LF, or LF form will be printed as one newline.
395       */
396      if (ch == '\r') {
397        fprintf(stderr, "\n");
398      } else if (ch == '\n') {
399        if (lastch != '\r')
400          fprintf(stderr, "\n");
401      } else if (ch == '\\') {
402        fprintf(stderr, "\\\\");
403      } else if (isprint(ch)) {
404        putc(ch, stderr);
405      } else {
406        fprintf(stderr, "\\%03o", ch);
407      }
408      lastch = ch;
409    }
410  }
411
412  if (traceit)
413    fprintf(stderr, "\n");
414
415  return TRUE;
416}
417
418
419/*
420 * The main program.
421 */
422
423int
424main (int argc, char **argv)
425{
426  struct jpeg_decompress_struct cinfo;
427  struct jpeg_error_mgr jerr;
428#ifdef PROGRESS_REPORT
429  struct cdjpeg_progress_mgr progress;
430#endif
431  int file_index;
432  djpeg_dest_ptr dest_mgr = NULL;
433  FILE * input_file;
434  FILE * output_file;
435  JDIMENSION num_scanlines;
436
437  /* On Mac, fetch a command line. */
438#ifdef USE_CCOMMAND
439  argc = ccommand(&argv);
440#endif
441
442  progname = argv[0];
443  if (progname == NULL || progname[0] == 0)
444    progname = "djpeg";         /* in case C library doesn't provide it */
445
446  /* Initialize the JPEG decompression object with default error handling. */
447  cinfo.err = jpeg_std_error(&jerr);
448  jpeg_create_decompress(&cinfo);
449  /* Add some application-specific error messages (from cderror.h) */
450  jerr.addon_message_table = cdjpeg_message_table;
451  jerr.first_addon_message = JMSG_FIRSTADDONCODE;
452  jerr.last_addon_message = JMSG_LASTADDONCODE;
453
454  /* Insert custom marker processor for COM and APP12.
455   * APP12 is used by some digital camera makers for textual info,
456   * so we provide the ability to display it as text.
457   * If you like, additional APPn marker types can be selected for display,
458   * but don't try to override APP0 or APP14 this way (see libjpeg.doc).
459   */
460  jpeg_set_marker_processor(&cinfo, JPEG_COM, print_text_marker);
461  jpeg_set_marker_processor(&cinfo, JPEG_APP0+12, print_text_marker);
462
463  /* Now safe to enable signal catcher. */
464#ifdef NEED_SIGNAL_CATCHER
465  enable_signal_catcher((j_common_ptr) &cinfo);
466#endif
467
468  /* Scan command line to find file names. */
469  /* It is convenient to use just one switch-parsing routine, but the switch
470   * values read here are ignored; we will rescan the switches after opening
471   * the input file.
472   * (Exception: tracing level set here controls verbosity for COM markers
473   * found during jpeg_read_header...)
474   */
475
476  file_index = parse_switches(&cinfo, argc, argv, 0, FALSE);
477
478#ifdef TWO_FILE_COMMANDLINE
479  /* Must have either -outfile switch or explicit output file name */
480  if (outfilename == NULL) {
481    if (file_index != argc-2) {
482      fprintf(stderr, "%s: must name one input and one output file\n",
483              progname);
484      usage();
485    }
486    outfilename = argv[file_index+1];
487  } else {
488    if (file_index != argc-1) {
489      fprintf(stderr, "%s: must name one input and one output file\n",
490              progname);
491      usage();
492    }
493  }
494#else
495  /* Unix style: expect zero or one file name */
496  if (file_index < argc-1) {
497    fprintf(stderr, "%s: only one input file\n", progname);
498    usage();
499  }
500#endif /* TWO_FILE_COMMANDLINE */
501
502  /* Open the input file. */
503  if (file_index < argc) {
504    if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
505      fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
506      exit(EXIT_FAILURE);
507    }
508  } else {
509    /* default input file is stdin */
510    input_file = read_stdin();
511  }
512
513  /* Open the output file. */
514  if (outfilename != NULL) {
515    if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
516      fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
517      exit(EXIT_FAILURE);
518    }
519  } else {
520    /* default output file is stdout */
521    output_file = write_stdout();
522  }
523
524#ifdef PROGRESS_REPORT
525  start_progress_monitor((j_common_ptr) &cinfo, &progress);
526#endif
527
528  /* Specify data source for decompression */
529  jpeg_stdio_src(&cinfo, input_file);
530
531  /* Read file header, set default decompression parameters */
532  (void) jpeg_read_header(&cinfo, TRUE);
533
534  /* Adjust default decompression parameters by re-parsing the options */
535  file_index = parse_switches(&cinfo, argc, argv, 0, TRUE);
536
537  /* Initialize the output module now to let it override any crucial
538   * option settings (for instance, GIF wants to force color quantization).
539   */
540  switch (requested_fmt) {
541#ifdef BMP_SUPPORTED
542  case FMT_BMP:
543    dest_mgr = jinit_write_bmp(&cinfo, FALSE);
544    break;
545  case FMT_OS2:
546    dest_mgr = jinit_write_bmp(&cinfo, TRUE);
547    break;
548#endif
549#ifdef GIF_SUPPORTED
550  case FMT_GIF:
551    dest_mgr = jinit_write_gif(&cinfo);
552    break;
553#endif
554#ifdef PPM_SUPPORTED
555  case FMT_PPM:
556    dest_mgr = jinit_write_ppm(&cinfo);
557    break;
558#endif
559#ifdef RLE_SUPPORTED
560  case FMT_RLE:
561    dest_mgr = jinit_write_rle(&cinfo);
562    break;
563#endif
564#ifdef TARGA_SUPPORTED
565  case FMT_TARGA:
566    dest_mgr = jinit_write_targa(&cinfo);
567    break;
568#endif
569  default:
570    ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT);
571    break;
572  }
573  dest_mgr->output_file = output_file;
574
575  /* Start decompressor */
576  (void) jpeg_start_decompress(&cinfo);
577
578  /* Write output file header */
579  (*dest_mgr->start_output) (&cinfo, dest_mgr);
580
581  /* Process data */
582  while (cinfo.output_scanline < cinfo.output_height) {
583    num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
584                                        dest_mgr->buffer_height);
585    (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
586  }
587
588#ifdef PROGRESS_REPORT
589  /* Hack: count final pass as done in case finish_output does an extra pass.
590   * The library won't have updated completed_passes.
591   */
592  progress.pub.completed_passes = progress.pub.total_passes;
593#endif
594
595  /* Finish decompression and release memory.
596   * I must do it in this order because output module has allocated memory
597   * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory.
598   */
599  (*dest_mgr->finish_output) (&cinfo, dest_mgr);
600  (void) jpeg_finish_decompress(&cinfo);
601  jpeg_destroy_decompress(&cinfo);
602
603  /* Close files, if we opened them */
604  if (input_file != stdin)
605    fclose(input_file);
606  if (output_file != stdout)
607    fclose(output_file);
608
609#ifdef PROGRESS_REPORT
610  end_progress_monitor((j_common_ptr) &cinfo);
611#endif
612
613  /* All done. */
614  exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);
615  return 0;                     /* suppress no-return-value warnings */
616}
Note: See TracBrowser for help on using the repository browser.