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 }