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