Home | History | Annotate | Download | only in libjpeg-turbo
      1 /*
      2  * djpeg.c
      3  *
      4  * This file was part of the Independent JPEG Group's software:
      5  * Copyright (C) 1991-1997, Thomas G. Lane.
      6  * libjpeg-turbo Modifications:
      7  * Copyright (C) 2010-2011, 2013-2016, D. R. Commander.
      8  * Copyright (C) 2015, Google, Inc.
      9  * For conditions of distribution and use, see the accompanying README file.
     10  *
     11  * This file contains a command-line user interface for the JPEG decompressor.
     12  * It should work on any system with Unix- or MS-DOS-style command lines.
     13  *
     14  * Two different command line styles are permitted, depending on the
     15  * compile-time switch TWO_FILE_COMMANDLINE:
     16  *      djpeg [options]  inputfile outputfile
     17  *      djpeg [options]  [inputfile]
     18  * In the second style, output is always to standard output, which you'd
     19  * normally redirect to a file or pipe to some other program.  Input is
     20  * either from a named file or from standard input (typically redirected).
     21  * The second style is convenient on Unix but is unhelpful on systems that
     22  * don't support pipes.  Also, you MUST use the first style if your system
     23  * doesn't do binary I/O to stdin/stdout.
     24  * To simplify script writing, the "-outfile" switch is provided.  The syntax
     25  *      djpeg [options]  -outfile outputfile  inputfile
     26  * works regardless of which command line style is used.
     27  */
     28 
     29 #include "cdjpeg.h"             /* Common decls for cjpeg/djpeg applications */
     30 #include "jversion.h"           /* for version message */
     31 #include "jconfigint.h"
     32 #include "wrppm.h"
     33 
     34 #include <ctype.h>              /* to declare isprint() */
     35 
     36 #ifdef USE_CCOMMAND             /* command-line reader for Macintosh */
     37 #ifdef __MWERKS__
     38 #include <SIOUX.h>              /* Metrowerks needs this */
     39 #include <console.h>            /* ... and this */
     40 #endif
     41 #ifdef THINK_C
     42 #include <console.h>            /* Think declares it here */
     43 #endif
     44 #endif
     45 
     46 
     47 /* Create the add-on message string table. */
     48 
     49 #define JMESSAGE(code,string)   string ,
     50 
     51 static const char * const cdjpeg_message_table[] = {
     52 #include "cderror.h"
     53   NULL
     54 };
     55 
     56 
     57 /*
     58  * This list defines the known output image formats
     59  * (not all of which need be supported by a given version).
     60  * You can change the default output format by defining DEFAULT_FMT;
     61  * indeed, you had better do so if you undefine PPM_SUPPORTED.
     62  */
     63 
     64 typedef enum {
     65         FMT_BMP,                /* BMP format (Windows flavor) */
     66         FMT_GIF,                /* GIF format */
     67         FMT_OS2,                /* BMP format (OS/2 flavor) */
     68         FMT_PPM,                /* PPM/PGM (PBMPLUS formats) */
     69         FMT_RLE,                /* RLE format */
     70         FMT_TARGA,              /* Targa format */
     71         FMT_TIFF                /* TIFF format */
     72 } IMAGE_FORMATS;
     73 
     74 #ifndef DEFAULT_FMT             /* so can override from CFLAGS in Makefile */
     75 #define DEFAULT_FMT     FMT_PPM
     76 #endif
     77 
     78 static IMAGE_FORMATS requested_fmt;
     79 
     80 
     81 /*
     82  * Argument-parsing code.
     83  * The switch parser is designed to be useful with DOS-style command line
     84  * syntax, ie, intermixed switches and file names, where only the switches
     85  * to the left of a given file name affect processing of that file.
     86  * The main program in this file doesn't actually use this capability...
     87  */
     88 
     89 
     90 static const char *progname;    /* program name for error messages */
     91 static char *outfilename;       /* for -outfile switch */
     92 boolean memsrc;                 /* for -memsrc switch */
     93 boolean skip, crop;
     94 JDIMENSION skip_start, skip_end;
     95 JDIMENSION crop_x, crop_y, crop_width, crop_height;
     96 #define INPUT_BUF_SIZE  4096
     97 
     98 
     99 LOCAL(void)
    100 usage (void)
    101 /* complain about bad command line */
    102 {
    103   fprintf(stderr, "usage: %s [switches] ", progname);
    104 #ifdef TWO_FILE_COMMANDLINE
    105   fprintf(stderr, "inputfile outputfile\n");
    106 #else
    107   fprintf(stderr, "[inputfile]\n");
    108 #endif
    109 
    110   fprintf(stderr, "Switches (names may be abbreviated):\n");
    111   fprintf(stderr, "  -colors N      Reduce image to no more than N colors\n");
    112   fprintf(stderr, "  -fast          Fast, low-quality processing\n");
    113   fprintf(stderr, "  -grayscale     Force grayscale output\n");
    114   fprintf(stderr, "  -rgb           Force RGB output\n");
    115   fprintf(stderr, "  -rgb565        Force RGB565 output\n");
    116 #ifdef IDCT_SCALING_SUPPORTED
    117   fprintf(stderr, "  -scale M/N     Scale output image by fraction M/N, eg, 1/8\n");
    118 #endif
    119 #ifdef BMP_SUPPORTED
    120   fprintf(stderr, "  -bmp           Select BMP output format (Windows style)%s\n",
    121           (DEFAULT_FMT == FMT_BMP ? " (default)" : ""));
    122 #endif
    123 #ifdef GIF_SUPPORTED
    124   fprintf(stderr, "  -gif           Select GIF output format%s\n",
    125           (DEFAULT_FMT == FMT_GIF ? " (default)" : ""));
    126 #endif
    127 #ifdef BMP_SUPPORTED
    128   fprintf(stderr, "  -os2           Select BMP output format (OS/2 style)%s\n",
    129           (DEFAULT_FMT == FMT_OS2 ? " (default)" : ""));
    130 #endif
    131 #ifdef PPM_SUPPORTED
    132   fprintf(stderr, "  -pnm           Select PBMPLUS (PPM/PGM) output format%s\n",
    133           (DEFAULT_FMT == FMT_PPM ? " (default)" : ""));
    134 #endif
    135 #ifdef RLE_SUPPORTED
    136   fprintf(stderr, "  -rle           Select Utah RLE output format%s\n",
    137           (DEFAULT_FMT == FMT_RLE ? " (default)" : ""));
    138 #endif
    139 #ifdef TARGA_SUPPORTED
    140   fprintf(stderr, "  -targa         Select Targa output format%s\n",
    141           (DEFAULT_FMT == FMT_TARGA ? " (default)" : ""));
    142 #endif
    143   fprintf(stderr, "Switches for advanced users:\n");
    144 #ifdef DCT_ISLOW_SUPPORTED
    145   fprintf(stderr, "  -dct int       Use integer DCT method%s\n",
    146           (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : ""));
    147 #endif
    148 #ifdef DCT_IFAST_SUPPORTED
    149   fprintf(stderr, "  -dct fast      Use fast integer DCT (less accurate)%s\n",
    150           (JDCT_DEFAULT == JDCT_IFAST ? " (default)" : ""));
    151 #endif
    152 #ifdef DCT_FLOAT_SUPPORTED
    153   fprintf(stderr, "  -dct float     Use floating-point DCT method%s\n",
    154           (JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : ""));
    155 #endif
    156   fprintf(stderr, "  -dither fs     Use F-S dithering (default)\n");
    157   fprintf(stderr, "  -dither none   Don't use dithering in quantization\n");
    158   fprintf(stderr, "  -dither ordered  Use ordered dither (medium speed, quality)\n");
    159 #ifdef QUANT_2PASS_SUPPORTED
    160   fprintf(stderr, "  -map FILE      Map to colors used in named image file\n");
    161 #endif
    162   fprintf(stderr, "  -nosmooth      Don't use high-quality upsampling\n");
    163 #ifdef QUANT_1PASS_SUPPORTED
    164   fprintf(stderr, "  -onepass       Use 1-pass quantization (fast, low quality)\n");
    165 #endif
    166   fprintf(stderr, "  -maxmemory N   Maximum memory to use (in kbytes)\n");
    167   fprintf(stderr, "  -outfile name  Specify name for output file\n");
    168 #if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
    169   fprintf(stderr, "  -memsrc        Load input file into memory before decompressing\n");
    170 #endif
    171 
    172   fprintf(stderr, "  -skip Y0,Y1    Decompress all rows except those between Y0 and Y1 (inclusive)\n");
    173   fprintf(stderr, "  -crop WxH+X+Y  Decompress only a rectangular subregion of the image\n");
    174   fprintf(stderr, "  -verbose  or  -debug   Emit debug output\n");
    175   fprintf(stderr, "  -version       Print version information and exit\n");
    176   exit(EXIT_FAILURE);
    177 }
    178 
    179 
    180 LOCAL(int)
    181 parse_switches (j_decompress_ptr cinfo, int argc, char **argv,
    182                 int last_file_arg_seen, boolean for_real)
    183 /* Parse optional switches.
    184  * Returns argv[] index of first file-name argument (== argc if none).
    185  * Any file names with indexes <= last_file_arg_seen are ignored;
    186  * they have presumably been processed in a previous iteration.
    187  * (Pass 0 for last_file_arg_seen on the first or only iteration.)
    188  * for_real is FALSE on the first (dummy) pass; we may skip any expensive
    189  * processing.
    190  */
    191 {
    192   int argn;
    193   char * arg;
    194 
    195   /* Set up default JPEG parameters. */
    196   requested_fmt = DEFAULT_FMT;  /* set default output file format */
    197   outfilename = NULL;
    198   memsrc = FALSE;
    199   skip = FALSE;
    200   crop = FALSE;
    201   cinfo->err->trace_level = 0;
    202 
    203   /* Scan command line options, adjust parameters */
    204 
    205   for (argn = 1; argn < argc; argn++) {
    206     arg = argv[argn];
    207     if (*arg != '-') {
    208       /* Not a switch, must be a file name argument */
    209       if (argn <= last_file_arg_seen) {
    210         outfilename = NULL;     /* -outfile applies to just one input file */
    211         continue;               /* ignore this name if previously processed */
    212       }
    213       break;                    /* else done parsing switches */
    214     }
    215     arg++;                      /* advance past switch marker character */
    216 
    217     if (keymatch(arg, "bmp", 1)) {
    218       /* BMP output format. */
    219       requested_fmt = FMT_BMP;
    220 
    221     } else if (keymatch(arg, "colors", 1) || keymatch(arg, "colours", 1) ||
    222                keymatch(arg, "quantize", 1) || keymatch(arg, "quantise", 1)) {
    223       /* Do color quantization. */
    224       int val;
    225 
    226       if (++argn >= argc)       /* advance to next argument */
    227         usage();
    228       if (sscanf(argv[argn], "%d", &val) != 1)
    229         usage();
    230       cinfo->desired_number_of_colors = val;
    231       cinfo->quantize_colors = TRUE;
    232 
    233     } else if (keymatch(arg, "dct", 2)) {
    234       /* Select IDCT algorithm. */
    235       if (++argn >= argc)       /* advance to next argument */
    236         usage();
    237       if (keymatch(argv[argn], "int", 1)) {
    238         cinfo->dct_method = JDCT_ISLOW;
    239       } else if (keymatch(argv[argn], "fast", 2)) {
    240         cinfo->dct_method = JDCT_IFAST;
    241       } else if (keymatch(argv[argn], "float", 2)) {
    242         cinfo->dct_method = JDCT_FLOAT;
    243       } else
    244         usage();
    245 
    246     } else if (keymatch(arg, "dither", 2)) {
    247       /* Select dithering algorithm. */
    248       if (++argn >= argc)       /* advance to next argument */
    249         usage();
    250       if (keymatch(argv[argn], "fs", 2)) {
    251         cinfo->dither_mode = JDITHER_FS;
    252       } else if (keymatch(argv[argn], "none", 2)) {
    253         cinfo->dither_mode = JDITHER_NONE;
    254       } else if (keymatch(argv[argn], "ordered", 2)) {
    255         cinfo->dither_mode = JDITHER_ORDERED;
    256       } else
    257         usage();
    258 
    259     } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
    260       /* Enable debug printouts. */
    261       /* On first -d, print version identification */
    262       static boolean printed_version = FALSE;
    263 
    264       if (! printed_version) {
    265         fprintf(stderr, "%s version %s (build %s)\n",
    266                 PACKAGE_NAME, VERSION, BUILD);
    267         fprintf(stderr, "%s\n\n", JCOPYRIGHT);
    268         fprintf(stderr, "Emulating The Independent JPEG Group's software, version %s\n\n",
    269                 JVERSION);
    270         printed_version = TRUE;
    271       }
    272       cinfo->err->trace_level++;
    273 
    274     } else if (keymatch(arg, "version", 4)) {
    275       fprintf(stderr, "%s version %s (build %s)\n",
    276               PACKAGE_NAME, VERSION, BUILD);
    277       exit(EXIT_SUCCESS);
    278 
    279     } else if (keymatch(arg, "fast", 1)) {
    280       /* Select recommended processing options for quick-and-dirty output. */
    281       cinfo->two_pass_quantize = FALSE;
    282       cinfo->dither_mode = JDITHER_ORDERED;
    283       if (! cinfo->quantize_colors) /* don't override an earlier -colors */
    284         cinfo->desired_number_of_colors = 216;
    285       cinfo->dct_method = JDCT_FASTEST;
    286       cinfo->do_fancy_upsampling = FALSE;
    287 
    288     } else if (keymatch(arg, "gif", 1)) {
    289       /* GIF output format. */
    290       requested_fmt = FMT_GIF;
    291 
    292     } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) {
    293       /* Force monochrome output. */
    294       cinfo->out_color_space = JCS_GRAYSCALE;
    295 
    296     } else if (keymatch(arg, "rgb", 2)) {
    297       /* Force RGB output. */
    298       cinfo->out_color_space = JCS_RGB;
    299 
    300     } else if (keymatch(arg, "rgb565", 2)) {
    301       /* Force RGB565 output. */
    302       cinfo->out_color_space = JCS_RGB565;
    303 
    304     } else if (keymatch(arg, "map", 3)) {
    305       /* Quantize to a color map taken from an input file. */
    306       if (++argn >= argc)       /* advance to next argument */
    307         usage();
    308       if (for_real) {           /* too expensive to do twice! */
    309 #ifdef QUANT_2PASS_SUPPORTED    /* otherwise can't quantize to supplied map */
    310         FILE * mapfile;
    311 
    312         if ((mapfile = fopen(argv[argn], READ_BINARY)) == NULL) {
    313           fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
    314           exit(EXIT_FAILURE);
    315         }
    316         read_color_map(cinfo, mapfile);
    317         fclose(mapfile);
    318         cinfo->quantize_colors = TRUE;
    319 #else
    320         ERREXIT(cinfo, JERR_NOT_COMPILED);
    321 #endif
    322       }
    323 
    324     } else if (keymatch(arg, "maxmemory", 3)) {
    325       /* Maximum memory in Kb (or Mb with 'm'). */
    326       long lval;
    327       char ch = 'x';
    328 
    329       if (++argn >= argc)       /* advance to next argument */
    330         usage();
    331       if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
    332         usage();
    333       if (ch == 'm' || ch == 'M')
    334         lval *= 1000L;
    335       cinfo->mem->max_memory_to_use = lval * 1000L;
    336 
    337     } else if (keymatch(arg, "nosmooth", 3)) {
    338       /* Suppress fancy upsampling */
    339       cinfo->do_fancy_upsampling = FALSE;
    340 
    341     } else if (keymatch(arg, "onepass", 3)) {
    342       /* Use fast one-pass quantization. */
    343       cinfo->two_pass_quantize = FALSE;
    344 
    345     } else if (keymatch(arg, "os2", 3)) {
    346       /* BMP output format (OS/2 flavor). */
    347       requested_fmt = FMT_OS2;
    348 
    349     } else if (keymatch(arg, "outfile", 4)) {
    350       /* Set output file name. */
    351       if (++argn >= argc)       /* advance to next argument */
    352         usage();
    353       outfilename = argv[argn]; /* save it away for later use */
    354 
    355     } else if (keymatch(arg, "memsrc", 2)) {
    356       /* Use in-memory source manager */
    357 #if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
    358       memsrc = TRUE;
    359 #else
    360       fprintf(stderr, "%s: sorry, in-memory source manager was not compiled in\n",
    361               progname);
    362       exit(EXIT_FAILURE);
    363 #endif
    364 
    365     } else if (keymatch(arg, "pnm", 1) || keymatch(arg, "ppm", 1)) {
    366       /* PPM/PGM output format. */
    367       requested_fmt = FMT_PPM;
    368 
    369     } else if (keymatch(arg, "rle", 1)) {
    370       /* RLE output format. */
    371       requested_fmt = FMT_RLE;
    372 
    373     } else if (keymatch(arg, "scale", 2)) {
    374       /* Scale the output image by a fraction M/N. */
    375       if (++argn >= argc)       /* advance to next argument */
    376         usage();
    377       if (sscanf(argv[argn], "%d/%d",
    378                  &cinfo->scale_num, &cinfo->scale_denom) != 2)
    379         usage();
    380 
    381     } else if (keymatch(arg, "skip", 2)) {
    382       if (++argn >= argc)
    383         usage();
    384       if (sscanf(argv[argn], "%u,%u", &skip_start, &skip_end) != 2 ||
    385           skip_start > skip_end)
    386         usage();
    387       skip = TRUE;
    388 
    389     } else if (keymatch(arg, "crop", 2)) {
    390       char c;
    391       if (++argn >= argc)
    392         usage();
    393       if (sscanf(argv[argn], "%u%c%u+%u+%u", &crop_width, &c, &crop_height,
    394                  &crop_x, &crop_y) != 5 ||
    395           (c != 'X' && c != 'x') || crop_width < 1 || crop_height < 1)
    396         usage();
    397       crop = TRUE;
    398 
    399     } else if (keymatch(arg, "targa", 1)) {
    400       /* Targa output format. */
    401       requested_fmt = FMT_TARGA;
    402 
    403     } else {
    404       usage();                  /* bogus switch */
    405     }
    406   }
    407 
    408   return argn;                  /* return index of next arg (file name) */
    409 }
    410 
    411 
    412 /*
    413  * Marker processor for COM and interesting APPn markers.
    414  * This replaces the library's built-in processor, which just skips the marker.
    415  * We want to print out the marker as text, to the extent possible.
    416  * Note this code relies on a non-suspending data source.
    417  */
    418 
    419 LOCAL(unsigned int)
    420 jpeg_getc (j_decompress_ptr cinfo)
    421 /* Read next byte */
    422 {
    423   struct jpeg_source_mgr * datasrc = cinfo->src;
    424 
    425   if (datasrc->bytes_in_buffer == 0) {
    426     if (! (*datasrc->fill_input_buffer) (cinfo))
    427       ERREXIT(cinfo, JERR_CANT_SUSPEND);
    428   }
    429   datasrc->bytes_in_buffer--;
    430   return GETJOCTET(*datasrc->next_input_byte++);
    431 }
    432 
    433 
    434 METHODDEF(boolean)
    435 print_text_marker (j_decompress_ptr cinfo)
    436 {
    437   boolean traceit = (cinfo->err->trace_level >= 1);
    438   INT32 length;
    439   unsigned int ch;
    440   unsigned int lastch = 0;
    441 
    442   length = jpeg_getc(cinfo) << 8;
    443   length += jpeg_getc(cinfo);
    444   length -= 2;                  /* discount the length word itself */
    445 
    446   if (traceit) {
    447     if (cinfo->unread_marker == JPEG_COM)
    448       fprintf(stderr, "Comment, length %ld:\n", (long) length);
    449     else                        /* assume it is an APPn otherwise */
    450       fprintf(stderr, "APP%d, length %ld:\n",
    451               cinfo->unread_marker - JPEG_APP0, (long) length);
    452   }
    453 
    454   while (--length >= 0) {
    455     ch = jpeg_getc(cinfo);
    456     if (traceit) {
    457       /* Emit the character in a readable form.
    458        * Nonprintables are converted to \nnn form,
    459        * while \ is converted to \\.
    460        * Newlines in CR, CR/LF, or LF form will be printed as one newline.
    461        */
    462       if (ch == '\r') {
    463         fprintf(stderr, "\n");
    464       } else if (ch == '\n') {
    465         if (lastch != '\r')
    466           fprintf(stderr, "\n");
    467       } else if (ch == '\\') {
    468         fprintf(stderr, "\\\\");
    469       } else if (isprint(ch)) {
    470         putc(ch, stderr);
    471       } else {
    472         fprintf(stderr, "\\%03o", ch);
    473       }
    474       lastch = ch;
    475     }
    476   }
    477 
    478   if (traceit)
    479     fprintf(stderr, "\n");
    480 
    481   return TRUE;
    482 }
    483 
    484 
    485 /*
    486  * The main program.
    487  */
    488 
    489 int
    490 main (int argc, char **argv)
    491 {
    492   struct jpeg_decompress_struct cinfo;
    493   struct jpeg_error_mgr jerr;
    494 #ifdef PROGRESS_REPORT
    495   struct cdjpeg_progress_mgr progress;
    496 #endif
    497   int file_index;
    498   djpeg_dest_ptr dest_mgr = NULL;
    499   FILE * input_file;
    500   FILE * output_file;
    501   unsigned char *inbuffer = NULL;
    502   unsigned long insize = 0;
    503   JDIMENSION num_scanlines;
    504 
    505   /* On Mac, fetch a command line. */
    506 #ifdef USE_CCOMMAND
    507   argc = ccommand(&argv);
    508 #endif
    509 
    510   progname = argv[0];
    511   if (progname == NULL || progname[0] == 0)
    512     progname = "djpeg";         /* in case C library doesn't provide it */
    513 
    514   /* Initialize the JPEG decompression object with default error handling. */
    515   cinfo.err = jpeg_std_error(&jerr);
    516   jpeg_create_decompress(&cinfo);
    517   /* Add some application-specific error messages (from cderror.h) */
    518   jerr.addon_message_table = cdjpeg_message_table;
    519   jerr.first_addon_message = JMSG_FIRSTADDONCODE;
    520   jerr.last_addon_message = JMSG_LASTADDONCODE;
    521 
    522   /* Insert custom marker processor for COM and APP12.
    523    * APP12 is used by some digital camera makers for textual info,
    524    * so we provide the ability to display it as text.
    525    * If you like, additional APPn marker types can be selected for display,
    526    * but don't try to override APP0 or APP14 this way (see libjpeg.txt).
    527    */
    528   jpeg_set_marker_processor(&cinfo, JPEG_COM, print_text_marker);
    529   jpeg_set_marker_processor(&cinfo, JPEG_APP0+12, print_text_marker);
    530 
    531   /* Scan command line to find file names. */
    532   /* It is convenient to use just one switch-parsing routine, but the switch
    533    * values read here are ignored; we will rescan the switches after opening
    534    * the input file.
    535    * (Exception: tracing level set here controls verbosity for COM markers
    536    * found during jpeg_read_header...)
    537    */
    538 
    539   file_index = parse_switches(&cinfo, argc, argv, 0, FALSE);
    540 
    541 #ifdef TWO_FILE_COMMANDLINE
    542   /* Must have either -outfile switch or explicit output file name */
    543   if (outfilename == NULL) {
    544     if (file_index != argc-2) {
    545       fprintf(stderr, "%s: must name one input and one output file\n",
    546               progname);
    547       usage();
    548     }
    549     outfilename = argv[file_index+1];
    550   } else {
    551     if (file_index != argc-1) {
    552       fprintf(stderr, "%s: must name one input and one output file\n",
    553               progname);
    554       usage();
    555     }
    556   }
    557 #else
    558   /* Unix style: expect zero or one file name */
    559   if (file_index < argc-1) {
    560     fprintf(stderr, "%s: only one input file\n", progname);
    561     usage();
    562   }
    563 #endif /* TWO_FILE_COMMANDLINE */
    564 
    565   /* Open the input file. */
    566   if (file_index < argc) {
    567     if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
    568       fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
    569       exit(EXIT_FAILURE);
    570     }
    571   } else {
    572     /* default input file is stdin */
    573     input_file = read_stdin();
    574   }
    575 
    576   /* Open the output file. */
    577   if (outfilename != NULL) {
    578     if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
    579       fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
    580       exit(EXIT_FAILURE);
    581     }
    582   } else {
    583     /* default output file is stdout */
    584     output_file = write_stdout();
    585   }
    586 
    587 #ifdef PROGRESS_REPORT
    588   start_progress_monitor((j_common_ptr) &cinfo, &progress);
    589 #endif
    590 
    591   /* Specify data source for decompression */
    592 #if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
    593   if (memsrc) {
    594     size_t nbytes;
    595     do {
    596       inbuffer = (unsigned char *)realloc(inbuffer, insize + INPUT_BUF_SIZE);
    597       if (inbuffer == NULL) {
    598         fprintf(stderr, "%s: memory allocation failure\n", progname);
    599         exit(EXIT_FAILURE);
    600       }
    601       nbytes = JFREAD(input_file, &inbuffer[insize], INPUT_BUF_SIZE);
    602       if (nbytes < INPUT_BUF_SIZE && ferror(input_file)) {
    603         if (file_index < argc)
    604           fprintf(stderr, "%s: can't read from %s\n", progname,
    605                   argv[file_index]);
    606         else
    607           fprintf(stderr, "%s: can't read from stdin\n", progname);
    608       }
    609       insize += (unsigned long)nbytes;
    610     } while (nbytes == INPUT_BUF_SIZE);
    611     fprintf(stderr, "Compressed size:  %lu bytes\n", insize);
    612     jpeg_mem_src(&cinfo, inbuffer, insize);
    613   } else
    614 #endif
    615     jpeg_stdio_src(&cinfo, input_file);
    616 
    617   /* Read file header, set default decompression parameters */
    618   (void) jpeg_read_header(&cinfo, TRUE);
    619 
    620   /* Adjust default decompression parameters by re-parsing the options */
    621   file_index = parse_switches(&cinfo, argc, argv, 0, TRUE);
    622 
    623   /* Initialize the output module now to let it override any crucial
    624    * option settings (for instance, GIF wants to force color quantization).
    625    */
    626   switch (requested_fmt) {
    627 #ifdef BMP_SUPPORTED
    628   case FMT_BMP:
    629     dest_mgr = jinit_write_bmp(&cinfo, FALSE);
    630     break;
    631   case FMT_OS2:
    632     dest_mgr = jinit_write_bmp(&cinfo, TRUE);
    633     break;
    634 #endif
    635 #ifdef GIF_SUPPORTED
    636   case FMT_GIF:
    637     dest_mgr = jinit_write_gif(&cinfo);
    638     break;
    639 #endif
    640 #ifdef PPM_SUPPORTED
    641   case FMT_PPM:
    642     dest_mgr = jinit_write_ppm(&cinfo);
    643     break;
    644 #endif
    645 #ifdef RLE_SUPPORTED
    646   case FMT_RLE:
    647     dest_mgr = jinit_write_rle(&cinfo);
    648     break;
    649 #endif
    650 #ifdef TARGA_SUPPORTED
    651   case FMT_TARGA:
    652     dest_mgr = jinit_write_targa(&cinfo);
    653     break;
    654 #endif
    655   default:
    656     ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT);
    657     break;
    658   }
    659   dest_mgr->output_file = output_file;
    660 
    661   /* Start decompressor */
    662   (void) jpeg_start_decompress(&cinfo);
    663 
    664   /* Skip rows */
    665   if (skip) {
    666     JDIMENSION tmp;
    667 
    668     /* Check for valid skip_end.  We cannot check this value until after
    669      * jpeg_start_decompress() is called.  Note that we have already verified
    670      * that skip_start <= skip_end.
    671      */
    672     if (skip_end > cinfo.output_height - 1) {
    673       fprintf(stderr, "%s: skip region exceeds image height %d\n", progname,
    674               cinfo.output_height);
    675       exit(EXIT_FAILURE);
    676     }
    677 
    678     /* Write output file header.  This is a hack to ensure that the destination
    679      * manager creates an output image of the proper size.
    680      */
    681     tmp = cinfo.output_height;
    682     cinfo.output_height -= (skip_end - skip_start + 1);
    683     (*dest_mgr->start_output) (&cinfo, dest_mgr);
    684     cinfo.output_height = tmp;
    685 
    686     /* Process data */
    687     while (cinfo.output_scanline < skip_start) {
    688       num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
    689                                           dest_mgr->buffer_height);
    690       (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
    691     }
    692     jpeg_skip_scanlines(&cinfo, skip_end - skip_start + 1);
    693     while (cinfo.output_scanline < cinfo.output_height) {
    694       num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
    695                                           dest_mgr->buffer_height);
    696       (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
    697     }
    698 
    699   /* Decompress a subregion */
    700   } else if (crop) {
    701     JDIMENSION tmp;
    702 
    703     /* Check for valid crop dimensions.  We cannot check these values until
    704      * after jpeg_start_decompress() is called.
    705      */
    706     if (crop_x + crop_width > cinfo.output_width ||
    707         crop_y + crop_height > cinfo.output_height) {
    708       fprintf(stderr, "%s: crop dimensions exceed image dimensions %d x %d\n",
    709               progname, cinfo.output_width, cinfo.output_height);
    710       exit(EXIT_FAILURE);
    711     }
    712 
    713     jpeg_crop_scanline(&cinfo, &crop_x, &crop_width);
    714     ((ppm_dest_ptr) dest_mgr)->buffer_width = cinfo.output_width *
    715                                               cinfo.out_color_components *
    716                                               sizeof(JSAMPLE);
    717 
    718     /* Write output file header.  This is a hack to ensure that the destination
    719      * manager creates an output image of the proper size.
    720      */
    721     tmp = cinfo.output_height;
    722     cinfo.output_height = crop_height;
    723     (*dest_mgr->start_output) (&cinfo, dest_mgr);
    724     cinfo.output_height = tmp;
    725 
    726     /* Process data */
    727     jpeg_skip_scanlines(&cinfo, crop_y);
    728     while (cinfo.output_scanline < crop_y + crop_height) {
    729       num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
    730                                           dest_mgr->buffer_height);
    731       (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
    732     }
    733     jpeg_skip_scanlines(&cinfo, cinfo.output_height - crop_y - crop_height);
    734 
    735   /* Normal full-image decompress */
    736   } else {
    737     /* Write output file header */
    738     (*dest_mgr->start_output) (&cinfo, dest_mgr);
    739 
    740     /* Process data */
    741     while (cinfo.output_scanline < cinfo.output_height) {
    742       num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
    743                                           dest_mgr->buffer_height);
    744       (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
    745     }
    746   }
    747 
    748 #ifdef PROGRESS_REPORT
    749   /* Hack: count final pass as done in case finish_output does an extra pass.
    750    * The library won't have updated completed_passes.
    751    */
    752   progress.pub.completed_passes = progress.pub.total_passes;
    753 #endif
    754 
    755   /* Finish decompression and release memory.
    756    * I must do it in this order because output module has allocated memory
    757    * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory.
    758    */
    759   (*dest_mgr->finish_output) (&cinfo, dest_mgr);
    760   (void) jpeg_finish_decompress(&cinfo);
    761   jpeg_destroy_decompress(&cinfo);
    762 
    763   /* Close files, if we opened them */
    764   if (input_file != stdin)
    765     fclose(input_file);
    766   if (output_file != stdout)
    767     fclose(output_file);
    768 
    769 #ifdef PROGRESS_REPORT
    770   end_progress_monitor((j_common_ptr) &cinfo);
    771 #endif
    772 
    773   if (memsrc && inbuffer != NULL)
    774     free(inbuffer);
    775 
    776   /* All done. */
    777   exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);
    778   return 0;                     /* suppress no-return-value warnings */
    779 }
    780