home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 4 / DATAFILE_PDCD4.iso / utilities / utilsf / jpegv6 / c / djpeg < prev    next >
Encoding:
Text File  |  1995-09-29  |  18.3 KB  |  604 lines

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