DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

jpegtran.cpp (12786B)


      1 /*
      2  * jpegtran.c
      3  *
      4  * Copyright (C) 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 JPEG transcoding.
      9  * It is very similar to cjpeg.c, but provides lossless transcoding between
     10  * different JPEG file formats.
     11  */
     12 
     13 #include "cdjpeg.h"      /* Common decls for cjpeg/djpeg applications */
     14 #include "jversion.h"        /* for version message */
     15 
     16 #ifdef USE_CCOMMAND     /* command-line reader for Macintosh */
     17 #ifdef __MWERKS__
     18 #include <SIOUX.h>              /* Metrowerks declares it here */
     19 #endif
     20 #ifdef THINK_C
     21 #include <console.h>     /* Think declares it here */
     22 #endif
     23 #endif
     24 
     25 
     26 /*
     27  * Argument-parsing code.
     28  * The switch parser is designed to be useful with DOS-style command line
     29  * syntax, ie, intermixed switches and file names, where only the switches
     30  * to the left of a given file name affect processing of that file.
     31  * The main program in this file doesn't actually use this capability...
     32  */
     33 
     34 
     35 static const char * progname;   /* program name for error messages */
     36 static char * outfilename;  /* for -outfile switch */
     37 
     38 
     39 LOCAL void
     40 usage( void ) {
     41 /* complain about bad command line */
     42     fprintf( stderr, "usage: %s [switches] ", progname );
     43 #ifdef TWO_FILE_COMMANDLINE
     44     fprintf( stderr, "inputfile outputfile\n" );
     45 #else
     46     fprintf( stderr, "[inputfile]\n" );
     47 #endif
     48 
     49     fprintf( stderr, "Switches (names may be abbreviated):\n" );
     50 #ifdef ENTROPY_OPT_SUPPORTED
     51     fprintf( stderr, "  -optimize      Optimize Huffman table (smaller file, but slow compression)\n" );
     52 #endif
     53 #ifdef C_PROGRESSIVE_SUPPORTED
     54     fprintf( stderr, "  -progressive   Create progressive JPEG file\n" );
     55 #endif
     56     fprintf( stderr, "Switches for advanced users:\n" );
     57     fprintf( stderr, "  -restart N     Set restart interval in rows, or in blocks with B\n" );
     58     fprintf( stderr, "  -maxmemory N   Maximum memory to use (in kbytes)\n" );
     59     fprintf( stderr, "  -outfile name  Specify name for output file\n" );
     60     fprintf( stderr, "  -verbose  or  -debug   Emit debug output\n" );
     61     fprintf( stderr, "Switches for wizards:\n" );
     62 #ifdef C_ARITH_CODING_SUPPORTED
     63     fprintf( stderr, "  -arithmetic    Use arithmetic coding\n" );
     64 #endif
     65 #ifdef C_MULTISCAN_FILES_SUPPORTED
     66     fprintf( stderr, "  -scans file    Create multi-scan JPEG per script file\n" );
     67 #endif
     68     exit( EXIT_FAILURE );
     69 }
     70 
     71 
     72 LOCAL int
     73 parse_switches( j_compress_ptr cinfo, int argc, char ** argv,
     74                 int last_file_arg_seen, boolean for_real ) {
     75 /* Parse optional switches.
     76  * Returns argv[] index of first file-name argument (== argc if none).
     77  * Any file names with indexes <= last_file_arg_seen are ignored;
     78  * they have presumably been processed in a previous iteration.
     79  * (Pass 0 for last_file_arg_seen on the first or only iteration.)
     80  * for_real is FALSE on the first (dummy) pass; we may skip any expensive
     81  * processing.
     82  */
     83     int argn;
     84     char * arg;
     85     boolean simple_progressive;
     86     char * scansarg = NULL; /* saves -scans parm if any */
     87 
     88     /* Set up default JPEG parameters. */
     89     simple_progressive = FALSE;
     90     outfilename = NULL;
     91     cinfo->err->trace_level = 0;
     92 
     93     /* Scan command line options, adjust parameters */
     94 
     95     for ( argn = 1; argn < argc; argn++ ) {
     96         arg = argv[argn];
     97         if ( *arg != '-' ) {
     98             /* Not a switch, must be a file name argument */
     99             if ( argn <= last_file_arg_seen ) {
    100                 outfilename = NULL;/* -outfile applies to just one input file */
    101                 continue; /* ignore this name if previously processed */
    102             }
    103             break;      /* else done parsing switches */
    104         }
    105         arg++;      /* advance past switch marker character */
    106 
    107         if ( keymatch( arg, "arithmetic", 1 ) ) {
    108             /* Use arithmetic coding. */
    109 #ifdef C_ARITH_CODING_SUPPORTED
    110             cinfo->arith_code = TRUE;
    111 #else
    112             fprintf( stderr, "%s: sorry, arithmetic coding not supported\n",
    113                      progname );
    114             exit( EXIT_FAILURE );
    115 #endif
    116 
    117         } else if ( keymatch( arg, "debug", 1 ) || keymatch( arg, "verbose", 1 ) ) {
    118             /* Enable debug printouts. */
    119             /* On first -d, print version identification */
    120             static boolean printed_version = FALSE;
    121 
    122             if ( !printed_version ) {
    123                 fprintf( stderr, "Independent JPEG Group's JPEGTRAN, version %s\n%s\n",
    124                          JVERSION, JCOPYRIGHT );
    125                 printed_version = TRUE;
    126             }
    127             cinfo->err->trace_level++;
    128 
    129         } else if ( keymatch( arg, "maxmemory", 3 ) ) {
    130             /* Maximum memory in Kb (or Mb with 'm'). */
    131             long lval;
    132             char ch = 'x';
    133 
    134             if ( ++argn >= argc ) {/* advance to next argument */
    135                 usage();
    136             }
    137             if ( sscanf( argv[argn], "%ld%c", &lval, &ch ) < 1 ) {
    138                 usage();
    139             }
    140             if ( ( ch == 'm' ) || ( ch == 'M' ) ) {
    141                 lval *= 1000L;
    142             }
    143             cinfo->mem->max_memory_to_use = lval * 1000L;
    144 
    145         } else if ( keymatch( arg, "optimize", 1 ) || keymatch( arg, "optimise", 1 ) ) {
    146             /* Enable entropy parm optimization. */
    147 #ifdef ENTROPY_OPT_SUPPORTED
    148             cinfo->optimize_coding = TRUE;
    149 #else
    150             fprintf( stderr, "%s: sorry, entropy optimization was not compiled\n",
    151                      progname );
    152             exit( EXIT_FAILURE );
    153 #endif
    154 
    155         } else if ( keymatch( arg, "outfile", 4 ) ) {
    156             /* Set output file name. */
    157             if ( ++argn >= argc ) {/* advance to next argument */
    158                 usage();
    159             }
    160             outfilename = argv[argn];/* save it away for later use */
    161 
    162         } else if ( keymatch( arg, "progressive", 1 ) ) {
    163             /* Select simple progressive mode. */
    164 #ifdef C_PROGRESSIVE_SUPPORTED
    165             simple_progressive = TRUE;
    166             /* We must postpone execution until num_components is known. */
    167 #else
    168             fprintf( stderr, "%s: sorry, progressive output was not compiled\n",
    169                      progname );
    170             exit( EXIT_FAILURE );
    171 #endif
    172 
    173         } else if ( keymatch( arg, "restart", 1 ) ) {
    174             /* Restart interval in MCU rows (or in MCUs with 'b'). */
    175             long lval;
    176             char ch = 'x';
    177 
    178             if ( ++argn >= argc ) {/* advance to next argument */
    179                 usage();
    180             }
    181             if ( sscanf( argv[argn], "%ld%c", &lval, &ch ) < 1 ) {
    182                 usage();
    183             }
    184             if ( ( lval < 0 ) || ( lval > 65535L ) ) {
    185                 usage();
    186             }
    187             if ( ( ch == 'b' ) || ( ch == 'B' ) ) {
    188                 cinfo->restart_interval = (unsigned int) lval;
    189                 cinfo->restart_in_rows = 0;/* else prior '-restart n' overrides me */
    190             } else {
    191                 cinfo->restart_in_rows = (int) lval;
    192                 /* restart_interval will be computed during startup */
    193             }
    194 
    195         } else if ( keymatch( arg, "scans", 2 ) ) {
    196             /* Set scan script. */
    197 #ifdef C_MULTISCAN_FILES_SUPPORTED
    198             if ( ++argn >= argc ) {/* advance to next argument */
    199                 usage();
    200             }
    201             scansarg = argv[argn];
    202             /* We must postpone reading the file in case -progressive appears. */
    203 #else
    204             fprintf( stderr, "%s: sorry, multi-scan output was not compiled\n",
    205                      progname );
    206             exit( EXIT_FAILURE );
    207 #endif
    208 
    209         } else {
    210             usage();    /* bogus switch */
    211         }
    212     }
    213 
    214     /* Post-switch-scanning cleanup */
    215 
    216     if ( for_real ) {
    217 
    218 #ifdef C_PROGRESSIVE_SUPPORTED
    219         if ( simple_progressive ) {/* process -progressive; -scans can override */
    220             jpeg_simple_progression( cinfo );
    221         }
    222 #endif
    223 
    224 #ifdef C_MULTISCAN_FILES_SUPPORTED
    225         if ( scansarg != NULL ) {/* process -scans if it was present */
    226             if ( !read_scan_script( cinfo, scansarg ) ) {
    227                 usage();
    228             }
    229         }
    230 #endif
    231     }
    232 
    233     return argn;        /* return index of next arg (file name) */
    234 }
    235 
    236 
    237 /*
    238  * The main program.
    239  */
    240 
    241 GLOBAL int
    242 main( int argc, char ** argv ) {
    243     struct jpeg_decompress_struct srcinfo;
    244     struct jpeg_compress_struct dstinfo;
    245     struct jpeg_error_mgr jsrcerr, jdsterr;
    246 #ifdef PROGRESS_REPORT
    247     struct cdjpeg_progress_mgr progress;
    248 #endif
    249     jvirt_barray_ptr * coef_arrays;
    250     int file_index;
    251     FILE * input_file;
    252     FILE * output_file;
    253 
    254     /* On Mac, fetch a command line. */
    255 #ifdef USE_CCOMMAND
    256     argc = ccommand( &argv );
    257 #endif
    258 
    259     progname = argv[0];
    260     if ( ( progname == NULL ) || ( progname[0] == 0 ) ) {
    261         progname = "jpegtran";
    262     }                       /* in case C library doesn't provide it */
    263 
    264     /* Initialize the JPEG decompression object with default error handling. */
    265     srcinfo.err = jpeg_std_error( &jsrcerr );
    266     jpeg_create_decompress( &srcinfo );
    267     /* Initialize the JPEG compression object with default error handling. */
    268     dstinfo.err = jpeg_std_error( &jdsterr );
    269     jpeg_create_compress( &dstinfo );
    270 
    271     /* Now safe to enable signal catcher.
    272      * Note: we assume only the decompression object will have virtual arrays.
    273      */
    274 #ifdef NEED_SIGNAL_CATCHER
    275     enable_signal_catcher( ( j_common_ptr ) & srcinfo );
    276 #endif
    277 
    278     /* Scan command line to find file names.
    279      * It is convenient to use just one switch-parsing routine, but the switch
    280      * values read here are ignored; we will rescan the switches after opening
    281      * the input file.
    282      */
    283 
    284     file_index = parse_switches( &dstinfo, argc, argv, 0, FALSE );
    285     jsrcerr.trace_level = jdsterr.trace_level;
    286 
    287 #ifdef TWO_FILE_COMMANDLINE
    288     /* Must have either -outfile switch or explicit output file name */
    289     if ( outfilename == NULL ) {
    290         if ( file_index != argc - 2 ) {
    291             fprintf( stderr, "%s: must name one input and one output file\n",
    292                      progname );
    293             usage();
    294         }
    295         outfilename = argv[file_index + 1];
    296     } else {
    297         if ( file_index != argc - 1 ) {
    298             fprintf( stderr, "%s: must name one input and one output file\n",
    299                      progname );
    300             usage();
    301         }
    302     }
    303 #else
    304     /* Unix style: expect zero or one file name */
    305     if ( file_index < argc - 1 ) {
    306         fprintf( stderr, "%s: only one input file\n", progname );
    307         usage();
    308     }
    309 #endif /* TWO_FILE_COMMANDLINE */
    310 
    311     /* Open the input file. */
    312     if ( file_index < argc ) {
    313         if ( ( input_file = fopen( argv[file_index], READ_BINARY ) ) == NULL ) {
    314             fprintf( stderr, "%s: can't open %s\n", progname, argv[file_index] );
    315             exit( EXIT_FAILURE );
    316         }
    317     } else {
    318         /* default input file is stdin */
    319         input_file = read_stdin();
    320     }
    321 
    322     /* Open the output file. */
    323     if ( outfilename != NULL ) {
    324         if ( ( output_file = fopen( outfilename, WRITE_BINARY ) ) == NULL ) {
    325             fprintf( stderr, "%s: can't open %s\n", progname, outfilename );
    326             exit( EXIT_FAILURE );
    327         }
    328     } else {
    329         /* default output file is stdout */
    330         output_file = write_stdout();
    331     }
    332 
    333 #ifdef PROGRESS_REPORT
    334     start_progress_monitor( ( j_common_ptr ) & dstinfo, &progress );
    335 #endif
    336 
    337     /* Specify data source for decompression */
    338     jpeg_stdio_src( &srcinfo, input_file );
    339 
    340     /* Read file header */
    341     (void) jpeg_read_header( &srcinfo, TRUE );
    342 
    343     /* Read source file as DCT coefficients */
    344     coef_arrays = jpeg_read_coefficients( &srcinfo );
    345 
    346     /* Initialize destination compression parameters from source values */
    347     jpeg_copy_critical_parameters( &srcinfo, &dstinfo );
    348 
    349     /* Adjust default compression parameters by re-parsing the options */
    350     file_index = parse_switches( &dstinfo, argc, argv, 0, TRUE );
    351 
    352     /* Specify data destination for compression */
    353     jpeg_stdio_dest( &dstinfo, output_file );
    354 
    355     /* Start compressor */
    356     jpeg_write_coefficients( &dstinfo, coef_arrays );
    357 
    358     /* ought to copy source comments here... */
    359 
    360     /* Finish compression and release memory */
    361     jpeg_finish_compress( &dstinfo );
    362     jpeg_destroy_compress( &dstinfo );
    363     (void) jpeg_finish_decompress( &srcinfo );
    364     jpeg_destroy_decompress( &srcinfo );
    365 
    366     /* Close files, if we opened them */
    367     if ( input_file != stdin ) {
    368         fclose( input_file );
    369     }
    370     if ( output_file != stdout ) {
    371         fclose( output_file );
    372     }
    373 
    374 #ifdef PROGRESS_REPORT
    375     end_progress_monitor( ( j_common_ptr ) & dstinfo );
    376 #endif
    377 
    378     /* All done. */
    379     exit( jsrcerr.num_warnings + jdsterr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS );
    380     return 0;       /* suppress no-return-value warnings */
    381 }