4  * Copyright (C) 1995-1997, 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. 
   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.  It also provides some lossless and sort-of- 
  11  * lossless transformations of JPEG data. 
  14 #include "cdjpeg.h"             /* Common decls for cjpeg/djpeg applications */ 
  15 #include "transupp.h"           /* Support routines for jpegtran */ 
  16 #include "jversion.h"           /* for version message */ 
  18 #ifdef USE_CCOMMAND             /* command-line reader for Macintosh */ 
  20 #include <SIOUX.h>              /* Metrowerks needs this */ 
  21 #include <console.h>            /* ... and this */ 
  24 #include <console.h>            /* Think declares it here */ 
  30  * Argument-parsing code. 
  31  * The switch parser is designed to be useful with DOS-style command line 
  32  * syntax, ie, intermixed switches and file names, where only the switches 
  33  * to the left of a given file name affect processing of that file. 
  34  * The main program in this file doesn't actually use this capability... 
  38 static const char * progname
;   /* program name for error messages */ 
  39 static char * outfilename
;      /* for -outfile switch */ 
  40 static JCOPY_OPTION copyoption
; /* -copy switch */ 
  41 static jpeg_transform_info transformoption
; /* image transformation options */ 
  46 /* complain about bad command line */ 
  48   fprintf(stderr
, "usage: %s [switches] ", progname
); 
  49 #ifdef TWO_FILE_COMMANDLINE 
  50   fprintf(stderr
, "inputfile outputfile\n"); 
  52   fprintf(stderr
, "[inputfile]\n"); 
  55   fprintf(stderr
, "Switches (names may be abbreviated):\n"); 
  56   fprintf(stderr
, "  -copy none     Copy no extra markers from source file\n"); 
  57   fprintf(stderr
, "  -copy comments Copy only comment markers (default)\n"); 
  58   fprintf(stderr
, "  -copy all      Copy all extra markers\n"); 
  59 #ifdef ENTROPY_OPT_SUPPORTED 
  60   fprintf(stderr
, "  -optimize      Optimize Huffman table (smaller file, but slow compression)\n"); 
  62 #ifdef C_PROGRESSIVE_SUPPORTED 
  63   fprintf(stderr
, "  -progressive   Create progressive JPEG file\n"); 
  65 #if TRANSFORMS_SUPPORTED 
  66   fprintf(stderr
, "Switches for modifying the image:\n"); 
  67   fprintf(stderr
, "  -grayscale     Reduce to grayscale (omit color data)\n"); 
  68   fprintf(stderr
, "  -flip [horizontal|vertical]  Mirror image (left-right or top-bottom)\n"); 
  69   fprintf(stderr
, "  -rotate [90|180|270]         Rotate image (degrees clockwise)\n"); 
  70   fprintf(stderr
, "  -transpose     Transpose image\n"); 
  71   fprintf(stderr
, "  -transverse    Transverse transpose image\n"); 
  72   fprintf(stderr
, "  -trim          Drop non-transformable edge blocks\n"); 
  73 #endif /* TRANSFORMS_SUPPORTED */ 
  74   fprintf(stderr
, "Switches for advanced users:\n"); 
  75   fprintf(stderr
, "  -restart N     Set restart interval in rows, or in blocks with B\n"); 
  76   fprintf(stderr
, "  -maxmemory N   Maximum memory to use (in kbytes)\n"); 
  77   fprintf(stderr
, "  -outfile name  Specify name for output file\n"); 
  78   fprintf(stderr
, "  -verbose  or  -debug   Emit debug output\n"); 
  79   fprintf(stderr
, "Switches for wizards:\n"); 
  80 #ifdef C_ARITH_CODING_SUPPORTED 
  81   fprintf(stderr
, "  -arithmetic    Use arithmetic coding\n"); 
  83 #ifdef C_MULTISCAN_FILES_SUPPORTED 
  84   fprintf(stderr
, "  -scans file    Create multi-scan JPEG per script file\n"); 
  91 select_transform (JXFORM_CODE transform
) 
  92 /* Silly little routine to detect multiple transform options, 
  93  * which we can't handle. 
  96 #if TRANSFORMS_SUPPORTED 
  97   if (transformoption
.transform 
== JXFORM_NONE 
|| 
  98       transformoption
.transform 
== transform
) { 
  99     transformoption
.transform 
= transform
; 
 101     fprintf(stderr
, "%s: can only do one image transformation at a time\n", 
 106   fprintf(stderr
, "%s: sorry, image transformation was not compiled\n", 
 114 parse_switches (j_compress_ptr cinfo
, int argc
, char **argv
, 
 115                 int last_file_arg_seen
, boolean for_real
) 
 116 /* Parse optional switches. 
 117  * Returns argv[] index of first file-name argument (== argc if none). 
 118  * Any file names with indexes <= last_file_arg_seen are ignored; 
 119  * they have presumably been processed in a previous iteration. 
 120  * (Pass 0 for last_file_arg_seen on the first or only iteration.) 
 121  * for_real is FALSE on the first (dummy) pass; we may skip any expensive 
 127   boolean simple_progressive
; 
 128   char * scansarg 
= NULL
;       /* saves -scans parm if any */ 
 130   /* Set up default JPEG parameters. */ 
 131   simple_progressive 
= FALSE
; 
 133   copyoption 
= JCOPYOPT_DEFAULT
; 
 134   transformoption
.transform 
= JXFORM_NONE
; 
 135   transformoption
.trim 
= FALSE
; 
 136   transformoption
.force_grayscale 
= FALSE
; 
 137   cinfo
->err
->trace_level 
= 0; 
 139   /* Scan command line options, adjust parameters */ 
 141   for (argn 
= 1; argn 
< argc
; argn
++) { 
 144       /* Not a switch, must be a file name argument */ 
 145       if (argn 
<= last_file_arg_seen
) { 
 146         outfilename 
= NULL
;     /* -outfile applies to just one input file */ 
 147         continue;               /* ignore this name if previously processed */ 
 149       break;                    /* else done parsing switches */ 
 151     arg
++;                      /* advance past switch marker character */ 
 153     if (keymatch(arg
, "arithmetic", 1)) { 
 154       /* Use arithmetic coding. */ 
 155 #ifdef C_ARITH_CODING_SUPPORTED 
 156       cinfo
->arith_code 
= TRUE
; 
 158       fprintf(stderr
, "%s: sorry, arithmetic coding not supported\n", 
 163     } else if (keymatch(arg
, "copy", 1)) { 
 164       /* Select which extra markers to copy. */ 
 165       if (++argn 
>= argc
)       /* advance to next argument */ 
 167       if (keymatch(argv
[argn
], "none", 1)) { 
 168         copyoption 
= JCOPYOPT_NONE
; 
 169       } else if (keymatch(argv
[argn
], "comments", 1)) { 
 170         copyoption 
= JCOPYOPT_COMMENTS
; 
 171       } else if (keymatch(argv
[argn
], "all", 1)) { 
 172         copyoption 
= JCOPYOPT_ALL
; 
 176     } else if (keymatch(arg
, "debug", 1) || keymatch(arg
, "verbose", 1)) { 
 177       /* Enable debug printouts. */ 
 178       /* On first -d, print version identification */ 
 179       static boolean printed_version 
= FALSE
; 
 181       if (! printed_version
) { 
 182         fprintf(stderr
, "Independent JPEG Group's JPEGTRAN, version %s\n%s\n", 
 183                 JVERSION
, JCOPYRIGHT
); 
 184         printed_version 
= TRUE
; 
 186       cinfo
->err
->trace_level
++; 
 188     } else if (keymatch(arg
, "flip", 1)) { 
 189       /* Mirror left-right or top-bottom. */ 
 190       if (++argn 
>= argc
)       /* advance to next argument */ 
 192       if (keymatch(argv
[argn
], "horizontal", 1)) 
 193         select_transform(JXFORM_FLIP_H
); 
 194       else if (keymatch(argv
[argn
], "vertical", 1)) 
 195         select_transform(JXFORM_FLIP_V
); 
 199     } else if (keymatch(arg
, "grayscale", 1) || keymatch(arg
, "greyscale",1)) { 
 200       /* Force to grayscale. */ 
 201 #if TRANSFORMS_SUPPORTED 
 202       transformoption
.force_grayscale 
= TRUE
; 
 204       select_transform(JXFORM_NONE
);    /* force an error */ 
 207     } else if (keymatch(arg
, "maxmemory", 3)) { 
 208       /* Maximum memory in Kb (or Mb with 'm'). */ 
 212       if (++argn 
>= argc
)       /* advance to next argument */ 
 214       if (sscanf(argv
[argn
], "%ld%c", &lval
, &ch
) < 1) 
 216       if (ch 
== 'm' || ch 
== 'M') 
 218       cinfo
->mem
->max_memory_to_use 
= lval 
* 1000L; 
 220     } else if (keymatch(arg
, "optimize", 1) || keymatch(arg
, "optimise", 1)) { 
 221       /* Enable entropy parm optimization. */ 
 222 #ifdef ENTROPY_OPT_SUPPORTED 
 223       cinfo
->optimize_coding 
= TRUE
; 
 225       fprintf(stderr
, "%s: sorry, entropy optimization was not compiled\n", 
 230     } else if (keymatch(arg
, "outfile", 4)) { 
 231       /* Set output file name. */ 
 232       if (++argn 
>= argc
)       /* advance to next argument */ 
 234       outfilename 
= argv
[argn
]; /* save it away for later use */ 
 236     } else if (keymatch(arg
, "progressive", 1)) { 
 237       /* Select simple progressive mode. */ 
 238 #ifdef C_PROGRESSIVE_SUPPORTED 
 239       simple_progressive 
= TRUE
; 
 240       /* We must postpone execution until num_components is known. */ 
 242       fprintf(stderr
, "%s: sorry, progressive output was not compiled\n", 
 247     } else if (keymatch(arg
, "restart", 1)) { 
 248       /* Restart interval in MCU rows (or in MCUs with 'b'). */ 
 252       if (++argn 
>= argc
)       /* advance to next argument */ 
 254       if (sscanf(argv
[argn
], "%ld%c", &lval
, &ch
) < 1) 
 256       if (lval 
< 0 || lval 
> 65535L) 
 258       if (ch 
== 'b' || ch 
== 'B') { 
 259         cinfo
->restart_interval 
= (unsigned int) lval
; 
 260         cinfo
->restart_in_rows 
= 0; /* else prior '-restart n' overrides me */ 
 262         cinfo
->restart_in_rows 
= (int) lval
; 
 263         /* restart_interval will be computed during startup */ 
 266     } else if (keymatch(arg
, "rotate", 2)) { 
 267       /* Rotate 90, 180, or 270 degrees (measured clockwise). */ 
 268       if (++argn 
>= argc
)       /* advance to next argument */ 
 270       if (keymatch(argv
[argn
], "90", 2)) 
 271         select_transform(JXFORM_ROT_90
); 
 272       else if (keymatch(argv
[argn
], "180", 3)) 
 273         select_transform(JXFORM_ROT_180
); 
 274       else if (keymatch(argv
[argn
], "270", 3)) 
 275         select_transform(JXFORM_ROT_270
); 
 279     } else if (keymatch(arg
, "scans", 1)) { 
 280       /* Set scan script. */ 
 281 #ifdef C_MULTISCAN_FILES_SUPPORTED 
 282       if (++argn 
>= argc
)       /* advance to next argument */ 
 284       scansarg 
= argv
[argn
]; 
 285       /* We must postpone reading the file in case -progressive appears. */ 
 287       fprintf(stderr
, "%s: sorry, multi-scan output was not compiled\n", 
 292     } else if (keymatch(arg
, "transpose", 1)) { 
 293       /* Transpose (across UL-to-LR axis). */ 
 294       select_transform(JXFORM_TRANSPOSE
); 
 296     } else if (keymatch(arg
, "transverse", 6)) { 
 297       /* Transverse transpose (across UR-to-LL axis). */ 
 298       select_transform(JXFORM_TRANSVERSE
); 
 300     } else if (keymatch(arg
, "trim", 3)) { 
 301       /* Trim off any partial edge MCUs that the transform can't handle. */ 
 302       transformoption
.trim 
= TRUE
; 
 305       usage();                  /* bogus switch */ 
 309   /* Post-switch-scanning cleanup */ 
 313 #ifdef C_PROGRESSIVE_SUPPORTED 
 314     if (simple_progressive
)     /* process -progressive; -scans can override */ 
 315       jpeg_simple_progression(cinfo
); 
 318 #ifdef C_MULTISCAN_FILES_SUPPORTED 
 319     if (scansarg 
!= NULL
)       /* process -scans if it was present */ 
 320       if (! read_scan_script(cinfo
, scansarg
)) 
 325   return argn
;                  /* return index of next arg (file name) */ 
 334 main (int argc
, char **argv
) 
 336   struct jpeg_decompress_struct srcinfo
; 
 337   struct jpeg_compress_struct dstinfo
; 
 338   struct jpeg_error_mgr jsrcerr
, jdsterr
; 
 339 #ifdef PROGRESS_REPORT 
 340   struct cdjpeg_progress_mgr progress
; 
 342   jvirt_barray_ptr 
* src_coef_arrays
; 
 343   jvirt_barray_ptr 
* dst_coef_arrays
; 
 348   /* On Mac, fetch a command line. */ 
 350   argc 
= ccommand(&argv
); 
 354   if (progname 
== NULL 
|| progname
[0] == 0) 
 355     progname 
= "jpegtran";      /* in case C library doesn't provide it */ 
 357   /* Initialize the JPEG decompression object with default error handling. */ 
 358   srcinfo
.err 
= jpeg_std_error(&jsrcerr
); 
 359   jpeg_create_decompress(&srcinfo
); 
 360   /* Initialize the JPEG compression object with default error handling. */ 
 361   dstinfo
.err 
= jpeg_std_error(&jdsterr
); 
 362   jpeg_create_compress(&dstinfo
); 
 364   /* Now safe to enable signal catcher. 
 365    * Note: we assume only the decompression object will have virtual arrays. 
 367 #ifdef NEED_SIGNAL_CATCHER 
 368   enable_signal_catcher((j_common_ptr
) &srcinfo
); 
 371   /* Scan command line to find file names. 
 372    * It is convenient to use just one switch-parsing routine, but the switch 
 373    * values read here are mostly ignored; we will rescan the switches after 
 374    * opening the input file.  Also note that most of the switches affect the 
 375    * destination JPEG object, so we parse into that and then copy over what 
 376    * needs to affects the source too. 
 379   file_index 
= parse_switches(&dstinfo
, argc
, argv
, 0, FALSE
); 
 380   jsrcerr
.trace_level 
= jdsterr
.trace_level
; 
 381   srcinfo
.mem
->max_memory_to_use 
= dstinfo
.mem
->max_memory_to_use
; 
 383 #ifdef TWO_FILE_COMMANDLINE 
 384   /* Must have either -outfile switch or explicit output file name */ 
 385   if (outfilename 
== NULL
) { 
 386     if (file_index 
!= argc
-2) { 
 387       fprintf(stderr
, "%s: must name one input and one output file\n", 
 391     outfilename 
= argv
[file_index
+1]; 
 393     if (file_index 
!= argc
-1) { 
 394       fprintf(stderr
, "%s: must name one input and one output file\n", 
 400   /* Unix style: expect zero or one file name */ 
 401   if (file_index 
< argc
-1) { 
 402     fprintf(stderr
, "%s: only one input file\n", progname
); 
 405 #endif /* TWO_FILE_COMMANDLINE */ 
 407   /* Open the input file. */ 
 408   if (file_index 
< argc
) { 
 409     if ((input_file 
= fopen(argv
[file_index
], READ_BINARY
)) == NULL
) { 
 410       fprintf(stderr
, "%s: can't open %s\n", progname
, argv
[file_index
]); 
 414     /* default input file is stdin */ 
 415     input_file 
= read_stdin(); 
 418   /* Open the output file. */ 
 419   if (outfilename 
!= NULL
) { 
 420     if ((output_file 
= fopen(outfilename
, WRITE_BINARY
)) == NULL
) { 
 421       fprintf(stderr
, "%s: can't open %s\n", progname
, outfilename
); 
 425     /* default output file is stdout */ 
 426     output_file 
= write_stdout(); 
 429 #ifdef PROGRESS_REPORT 
 430   start_progress_monitor((j_common_ptr
) &dstinfo
, &progress
); 
 433   /* Specify data source for decompression */ 
 434   jpeg_stdio_src(&srcinfo
, input_file
); 
 436   /* Enable saving of extra markers that we want to copy */ 
 437   jcopy_markers_setup(&srcinfo
, copyoption
); 
 439   /* Read file header */ 
 440   (void) jpeg_read_header(&srcinfo
, TRUE
); 
 442   /* Any space needed by a transform option must be requested before 
 443    * jpeg_read_coefficients so that memory allocation will be done right. 
 445 #if TRANSFORMS_SUPPORTED 
 446   jtransform_request_workspace(&srcinfo
, &transformoption
); 
 449   /* Read source file as DCT coefficients */ 
 450   src_coef_arrays 
= jpeg_read_coefficients(&srcinfo
); 
 452   /* Initialize destination compression parameters from source values */ 
 453   jpeg_copy_critical_parameters(&srcinfo
, &dstinfo
); 
 455   /* Adjust destination parameters if required by transform options; 
 456    * also find out which set of coefficient arrays will hold the output. 
 458 #if TRANSFORMS_SUPPORTED 
 459   dst_coef_arrays 
= jtransform_adjust_parameters(&srcinfo
, &dstinfo
, 
 463   dst_coef_arrays 
= src_coef_arrays
; 
 466   /* Adjust default compression parameters by re-parsing the options */ 
 467   file_index 
= parse_switches(&dstinfo
, argc
, argv
, 0, TRUE
); 
 469   /* Specify data destination for compression */ 
 470   jpeg_stdio_dest(&dstinfo
, output_file
); 
 472   /* Start compressor (note no image data is actually written here) */ 
 473   jpeg_write_coefficients(&dstinfo
, dst_coef_arrays
); 
 475   /* Copy to the output file any extra markers that we want to preserve */ 
 476   jcopy_markers_execute(&srcinfo
, &dstinfo
, copyoption
); 
 478   /* Execute image transformation, if any */ 
 479 #if TRANSFORMS_SUPPORTED 
 480   jtransform_execute_transformation(&srcinfo
, &dstinfo
, 
 485   /* Finish compression and release memory */ 
 486   jpeg_finish_compress(&dstinfo
); 
 487   jpeg_destroy_compress(&dstinfo
); 
 488   (void) jpeg_finish_decompress(&srcinfo
); 
 489   jpeg_destroy_decompress(&srcinfo
); 
 491   /* Close files, if we opened them */ 
 492   if (input_file 
!= stdin
) 
 494   if (output_file 
!= stdout
) 
 497 #ifdef PROGRESS_REPORT 
 498   end_progress_monitor((j_common_ptr
) &dstinfo
); 
 502   exit(jsrcerr
.num_warnings 
+ jdsterr
.num_warnings 
?EXIT_WARNING
:EXIT_SUCCESS
); 
 503   return 0;                     /* suppress no-return-value warnings */