Back to index

plt-scheme  4.2.1
jpegtran.c
Go to the documentation of this file.
00001 /*
00002  * jpegtran.c
00003  *
00004  * Copyright (C) 1995-1997, Thomas G. Lane.
00005  * This file is part of the Independent JPEG Group's software.
00006  * For conditions of distribution and use, see the accompanying README file.
00007  *
00008  * This file contains a command-line user interface for JPEG transcoding.
00009  * It is very similar to cjpeg.c, but provides lossless transcoding between
00010  * different JPEG file formats.  It also provides some lossless and sort-of-
00011  * lossless transformations of JPEG data.
00012  */
00013 
00014 #include "cdjpeg.h"         /* Common decls for cjpeg/djpeg applications */
00015 #include "transupp.h"              /* Support routines for jpegtran */
00016 #include "jversion.h"              /* for version message */
00017 
00018 #ifdef USE_CCOMMAND         /* command-line reader for Macintosh */
00019 #ifdef __MWERKS__
00020 #include <SIOUX.h>              /* Metrowerks needs this */
00021 #include <console.h>        /* ... and this */
00022 #endif
00023 #ifdef THINK_C
00024 #include <console.h>        /* Think declares it here */
00025 #endif
00026 #endif
00027 
00028 
00029 /*
00030  * Argument-parsing code.
00031  * The switch parser is designed to be useful with DOS-style command line
00032  * syntax, ie, intermixed switches and file names, where only the switches
00033  * to the left of a given file name affect processing of that file.
00034  * The main program in this file doesn't actually use this capability...
00035  */
00036 
00037 
00038 static const char * progname;      /* program name for error messages */
00039 static char * outfilename;  /* for -outfile switch */
00040 static JCOPY_OPTION copyoption;    /* -copy switch */
00041 static jpeg_transform_info transformoption; /* image transformation options */
00042 
00043 
00044 LOCAL(void)
00045 usage (void)
00046 /* complain about bad command line */
00047 {
00048   fprintf(stderr, "usage: %s [switches] ", progname);
00049 #ifdef TWO_FILE_COMMANDLINE
00050   fprintf(stderr, "inputfile outputfile\n");
00051 #else
00052   fprintf(stderr, "[inputfile]\n");
00053 #endif
00054 
00055   fprintf(stderr, "Switches (names may be abbreviated):\n");
00056   fprintf(stderr, "  -copy none     Copy no extra markers from source file\n");
00057   fprintf(stderr, "  -copy comments Copy only comment markers (default)\n");
00058   fprintf(stderr, "  -copy all      Copy all extra markers\n");
00059 #ifdef ENTROPY_OPT_SUPPORTED
00060   fprintf(stderr, "  -optimize      Optimize Huffman table (smaller file, but slow compression)\n");
00061 #endif
00062 #ifdef C_PROGRESSIVE_SUPPORTED
00063   fprintf(stderr, "  -progressive   Create progressive JPEG file\n");
00064 #endif
00065 #if TRANSFORMS_SUPPORTED
00066   fprintf(stderr, "Switches for modifying the image:\n");
00067   fprintf(stderr, "  -grayscale     Reduce to grayscale (omit color data)\n");
00068   fprintf(stderr, "  -flip [horizontal|vertical]  Mirror image (left-right or top-bottom)\n");
00069   fprintf(stderr, "  -rotate [90|180|270]         Rotate image (degrees clockwise)\n");
00070   fprintf(stderr, "  -transpose     Transpose image\n");
00071   fprintf(stderr, "  -transverse    Transverse transpose image\n");
00072   fprintf(stderr, "  -trim          Drop non-transformable edge blocks\n");
00073 #endif /* TRANSFORMS_SUPPORTED */
00074   fprintf(stderr, "Switches for advanced users:\n");
00075   fprintf(stderr, "  -restart N     Set restart interval in rows, or in blocks with B\n");
00076   fprintf(stderr, "  -maxmemory N   Maximum memory to use (in kbytes)\n");
00077   fprintf(stderr, "  -outfile name  Specify name for output file\n");
00078   fprintf(stderr, "  -verbose  or  -debug   Emit debug output\n");
00079   fprintf(stderr, "Switches for wizards:\n");
00080 #ifdef C_ARITH_CODING_SUPPORTED
00081   fprintf(stderr, "  -arithmetic    Use arithmetic coding\n");
00082 #endif
00083 #ifdef C_MULTISCAN_FILES_SUPPORTED
00084   fprintf(stderr, "  -scans file    Create multi-scan JPEG per script file\n");
00085 #endif
00086   exit(EXIT_FAILURE);
00087 }
00088 
00089 
00090 LOCAL(void)
00091 select_transform (JXFORM_CODE transform)
00092 /* Silly little routine to detect multiple transform options,
00093  * which we can't handle.
00094  */
00095 {
00096 #if TRANSFORMS_SUPPORTED
00097   if (transformoption.transform == JXFORM_NONE ||
00098       transformoption.transform == transform) {
00099     transformoption.transform = transform;
00100   } else {
00101     fprintf(stderr, "%s: can only do one image transformation at a time\n",
00102            progname);
00103     usage();
00104   }
00105 #else
00106   fprintf(stderr, "%s: sorry, image transformation was not compiled\n",
00107          progname);
00108   exit(EXIT_FAILURE);
00109 #endif
00110 }
00111 
00112 
00113 LOCAL(int)
00114 parse_switches (j_compress_ptr cinfo, int argc, char **argv,
00115               int last_file_arg_seen, boolean for_real)
00116 /* Parse optional switches.
00117  * Returns argv[] index of first file-name argument (== argc if none).
00118  * Any file names with indexes <= last_file_arg_seen are ignored;
00119  * they have presumably been processed in a previous iteration.
00120  * (Pass 0 for last_file_arg_seen on the first or only iteration.)
00121  * for_real is FALSE on the first (dummy) pass; we may skip any expensive
00122  * processing.
00123  */
00124 {
00125   int argn;
00126   char * arg;
00127   boolean simple_progressive;
00128   char * scansarg = NULL;   /* saves -scans parm if any */
00129 
00130   /* Set up default JPEG parameters. */
00131   simple_progressive = FALSE;
00132   outfilename = NULL;
00133   copyoption = JCOPYOPT_DEFAULT;
00134   transformoption.transform = JXFORM_NONE;
00135   transformoption.trim = FALSE;
00136   transformoption.force_grayscale = FALSE;
00137   cinfo->err->trace_level = 0;
00138 
00139   /* Scan command line options, adjust parameters */
00140 
00141   for (argn = 1; argn < argc; argn++) {
00142     arg = argv[argn];
00143     if (*arg != '-') {
00144       /* Not a switch, must be a file name argument */
00145       if (argn <= last_file_arg_seen) {
00146        outfilename = NULL;  /* -outfile applies to just one input file */
00147        continue;            /* ignore this name if previously processed */
00148       }
00149       break;                /* else done parsing switches */
00150     }
00151     arg++;                  /* advance past switch marker character */
00152 
00153     if (keymatch(arg, "arithmetic", 1)) {
00154       /* Use arithmetic coding. */
00155 #ifdef C_ARITH_CODING_SUPPORTED
00156       cinfo->arith_code = TRUE;
00157 #else
00158       fprintf(stderr, "%s: sorry, arithmetic coding not supported\n",
00159              progname);
00160       exit(EXIT_FAILURE);
00161 #endif
00162 
00163     } else if (keymatch(arg, "copy", 1)) {
00164       /* Select which extra markers to copy. */
00165       if (++argn >= argc)   /* advance to next argument */
00166        usage();
00167       if (keymatch(argv[argn], "none", 1)) {
00168        copyoption = JCOPYOPT_NONE;
00169       } else if (keymatch(argv[argn], "comments", 1)) {
00170        copyoption = JCOPYOPT_COMMENTS;
00171       } else if (keymatch(argv[argn], "all", 1)) {
00172        copyoption = JCOPYOPT_ALL;
00173       } else
00174        usage();
00175 
00176     } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
00177       /* Enable debug printouts. */
00178       /* On first -d, print version identification */
00179       static boolean printed_version = FALSE;
00180 
00181       if (! printed_version) {
00182        fprintf(stderr, "Independent JPEG Group's JPEGTRAN, version %s\n%s\n",
00183               JVERSION, JCOPYRIGHT);
00184        printed_version = TRUE;
00185       }
00186       cinfo->err->trace_level++;
00187 
00188     } else if (keymatch(arg, "flip", 1)) {
00189       /* Mirror left-right or top-bottom. */
00190       if (++argn >= argc)   /* advance to next argument */
00191        usage();
00192       if (keymatch(argv[argn], "horizontal", 1))
00193        select_transform(JXFORM_FLIP_H);
00194       else if (keymatch(argv[argn], "vertical", 1))
00195        select_transform(JXFORM_FLIP_V);
00196       else
00197        usage();
00198 
00199     } else if (keymatch(arg, "grayscale", 1) || keymatch(arg, "greyscale",1)) {
00200       /* Force to grayscale. */
00201 #if TRANSFORMS_SUPPORTED
00202       transformoption.force_grayscale = TRUE;
00203 #else
00204       select_transform(JXFORM_NONE);      /* force an error */
00205 #endif
00206 
00207     } else if (keymatch(arg, "maxmemory", 3)) {
00208       /* Maximum memory in Kb (or Mb with 'm'). */
00209       long lval;
00210       char ch = 'x';
00211 
00212       if (++argn >= argc)   /* advance to next argument */
00213        usage();
00214       if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
00215        usage();
00216       if (ch == 'm' || ch == 'M')
00217        lval *= 1000L;
00218       cinfo->mem->max_memory_to_use = lval * 1000L;
00219 
00220     } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) {
00221       /* Enable entropy parm optimization. */
00222 #ifdef ENTROPY_OPT_SUPPORTED
00223       cinfo->optimize_coding = TRUE;
00224 #else
00225       fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n",
00226              progname);
00227       exit(EXIT_FAILURE);
00228 #endif
00229 
00230     } else if (keymatch(arg, "outfile", 4)) {
00231       /* Set output file name. */
00232       if (++argn >= argc)   /* advance to next argument */
00233        usage();
00234       outfilename = argv[argn];    /* save it away for later use */
00235 
00236     } else if (keymatch(arg, "progressive", 1)) {
00237       /* Select simple progressive mode. */
00238 #ifdef C_PROGRESSIVE_SUPPORTED
00239       simple_progressive = TRUE;
00240       /* We must postpone execution until num_components is known. */
00241 #else
00242       fprintf(stderr, "%s: sorry, progressive output was not compiled\n",
00243              progname);
00244       exit(EXIT_FAILURE);
00245 #endif
00246 
00247     } else if (keymatch(arg, "restart", 1)) {
00248       /* Restart interval in MCU rows (or in MCUs with 'b'). */
00249       long lval;
00250       char ch = 'x';
00251 
00252       if (++argn >= argc)   /* advance to next argument */
00253        usage();
00254       if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
00255        usage();
00256       if (lval < 0 || lval > 65535L)
00257        usage();
00258       if (ch == 'b' || ch == 'B') {
00259        cinfo->restart_interval = (unsigned int) lval;
00260        cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */
00261       } else {
00262        cinfo->restart_in_rows = (int) lval;
00263        /* restart_interval will be computed during startup */
00264       }
00265 
00266     } else if (keymatch(arg, "rotate", 2)) {
00267       /* Rotate 90, 180, or 270 degrees (measured clockwise). */
00268       if (++argn >= argc)   /* advance to next argument */
00269        usage();
00270       if (keymatch(argv[argn], "90", 2))
00271        select_transform(JXFORM_ROT_90);
00272       else if (keymatch(argv[argn], "180", 3))
00273        select_transform(JXFORM_ROT_180);
00274       else if (keymatch(argv[argn], "270", 3))
00275        select_transform(JXFORM_ROT_270);
00276       else
00277        usage();
00278 
00279     } else if (keymatch(arg, "scans", 1)) {
00280       /* Set scan script. */
00281 #ifdef C_MULTISCAN_FILES_SUPPORTED
00282       if (++argn >= argc)   /* advance to next argument */
00283        usage();
00284       scansarg = argv[argn];
00285       /* We must postpone reading the file in case -progressive appears. */
00286 #else
00287       fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n",
00288              progname);
00289       exit(EXIT_FAILURE);
00290 #endif
00291 
00292     } else if (keymatch(arg, "transpose", 1)) {
00293       /* Transpose (across UL-to-LR axis). */
00294       select_transform(JXFORM_TRANSPOSE);
00295 
00296     } else if (keymatch(arg, "transverse", 6)) {
00297       /* Transverse transpose (across UR-to-LL axis). */
00298       select_transform(JXFORM_TRANSVERSE);
00299 
00300     } else if (keymatch(arg, "trim", 3)) {
00301       /* Trim off any partial edge MCUs that the transform can't handle. */
00302       transformoption.trim = TRUE;
00303 
00304     } else {
00305       usage();                     /* bogus switch */
00306     }
00307   }
00308 
00309   /* Post-switch-scanning cleanup */
00310 
00311   if (for_real) {
00312 
00313 #ifdef C_PROGRESSIVE_SUPPORTED
00314     if (simple_progressive) /* process -progressive; -scans can override */
00315       jpeg_simple_progression(cinfo);
00316 #endif
00317 
00318 #ifdef C_MULTISCAN_FILES_SUPPORTED
00319     if (scansarg != NULL)   /* process -scans if it was present */
00320       if (! read_scan_script(cinfo, scansarg))
00321        usage();
00322 #endif
00323   }
00324 
00325   return argn;                     /* return index of next arg (file name) */
00326 }
00327 
00328 
00329 /*
00330  * The main program.
00331  */
00332 
00333 int
00334 main (int argc, char **argv)
00335 {
00336   struct jpeg_decompress_struct srcinfo;
00337   struct jpeg_compress_struct dstinfo;
00338   struct jpeg_error_mgr jsrcerr, jdsterr;
00339 #ifdef PROGRESS_REPORT
00340   struct cdjpeg_progress_mgr progress;
00341 #endif
00342   jvirt_barray_ptr * src_coef_arrays;
00343   jvirt_barray_ptr * dst_coef_arrays;
00344   int file_index;
00345   FILE * input_file;
00346   FILE * output_file;
00347 
00348   /* On Mac, fetch a command line. */
00349 #ifdef USE_CCOMMAND
00350   argc = ccommand(&argv);
00351 #endif
00352 
00353   progname = argv[0];
00354   if (progname == NULL || progname[0] == 0)
00355     progname = "jpegtran";  /* in case C library doesn't provide it */
00356 
00357   /* Initialize the JPEG decompression object with default error handling. */
00358   srcinfo.err = jpeg_std_error(&jsrcerr);
00359   jpeg_create_decompress(&srcinfo);
00360   /* Initialize the JPEG compression object with default error handling. */
00361   dstinfo.err = jpeg_std_error(&jdsterr);
00362   jpeg_create_compress(&dstinfo);
00363 
00364   /* Now safe to enable signal catcher.
00365    * Note: we assume only the decompression object will have virtual arrays.
00366    */
00367 #ifdef NEED_SIGNAL_CATCHER
00368   enable_signal_catcher((j_common_ptr) &srcinfo);
00369 #endif
00370 
00371   /* Scan command line to find file names.
00372    * It is convenient to use just one switch-parsing routine, but the switch
00373    * values read here are mostly ignored; we will rescan the switches after
00374    * opening the input file.  Also note that most of the switches affect the
00375    * destination JPEG object, so we parse into that and then copy over what
00376    * needs to affects the source too.
00377    */
00378 
00379   file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE);
00380   jsrcerr.trace_level = jdsterr.trace_level;
00381   srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use;
00382 
00383 #ifdef TWO_FILE_COMMANDLINE
00384   /* Must have either -outfile switch or explicit output file name */
00385   if (outfilename == NULL) {
00386     if (file_index != argc-2) {
00387       fprintf(stderr, "%s: must name one input and one output file\n",
00388              progname);
00389       usage();
00390     }
00391     outfilename = argv[file_index+1];
00392   } else {
00393     if (file_index != argc-1) {
00394       fprintf(stderr, "%s: must name one input and one output file\n",
00395              progname);
00396       usage();
00397     }
00398   }
00399 #else
00400   /* Unix style: expect zero or one file name */
00401   if (file_index < argc-1) {
00402     fprintf(stderr, "%s: only one input file\n", progname);
00403     usage();
00404   }
00405 #endif /* TWO_FILE_COMMANDLINE */
00406 
00407   /* Open the input file. */
00408   if (file_index < argc) {
00409     if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
00410       fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
00411       exit(EXIT_FAILURE);
00412     }
00413   } else {
00414     /* default input file is stdin */
00415     input_file = read_stdin();
00416   }
00417 
00418   /* Open the output file. */
00419   if (outfilename != NULL) {
00420     if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
00421       fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
00422       exit(EXIT_FAILURE);
00423     }
00424   } else {
00425     /* default output file is stdout */
00426     output_file = write_stdout();
00427   }
00428 
00429 #ifdef PROGRESS_REPORT
00430   start_progress_monitor((j_common_ptr) &dstinfo, &progress);
00431 #endif
00432 
00433   /* Specify data source for decompression */
00434   jpeg_stdio_src(&srcinfo, input_file);
00435 
00436   /* Enable saving of extra markers that we want to copy */
00437   jcopy_markers_setup(&srcinfo, copyoption);
00438 
00439   /* Read file header */
00440   (void) jpeg_read_header(&srcinfo, TRUE);
00441 
00442   /* Any space needed by a transform option must be requested before
00443    * jpeg_read_coefficients so that memory allocation will be done right.
00444    */
00445 #if TRANSFORMS_SUPPORTED
00446   jtransform_request_workspace(&srcinfo, &transformoption);
00447 #endif
00448 
00449   /* Read source file as DCT coefficients */
00450   src_coef_arrays = jpeg_read_coefficients(&srcinfo);
00451 
00452   /* Initialize destination compression parameters from source values */
00453   jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
00454 
00455   /* Adjust destination parameters if required by transform options;
00456    * also find out which set of coefficient arrays will hold the output.
00457    */
00458 #if TRANSFORMS_SUPPORTED
00459   dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo,
00460                                            src_coef_arrays,
00461                                            &transformoption);
00462 #else
00463   dst_coef_arrays = src_coef_arrays;
00464 #endif
00465 
00466   /* Adjust default compression parameters by re-parsing the options */
00467   file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE);
00468 
00469   /* Specify data destination for compression */
00470   jpeg_stdio_dest(&dstinfo, output_file);
00471 
00472   /* Start compressor (note no image data is actually written here) */
00473   jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
00474 
00475   /* Copy to the output file any extra markers that we want to preserve */
00476   jcopy_markers_execute(&srcinfo, &dstinfo, copyoption);
00477 
00478   /* Execute image transformation, if any */
00479 #if TRANSFORMS_SUPPORTED
00480   jtransform_execute_transformation(&srcinfo, &dstinfo,
00481                                 src_coef_arrays,
00482                                 &transformoption);
00483 #endif
00484 
00485   /* Finish compression and release memory */
00486   jpeg_finish_compress(&dstinfo);
00487   jpeg_destroy_compress(&dstinfo);
00488   (void) jpeg_finish_decompress(&srcinfo);
00489   jpeg_destroy_decompress(&srcinfo);
00490 
00491   /* Close files, if we opened them */
00492   if (input_file != stdin)
00493     fclose(input_file);
00494   if (output_file != stdout)
00495     fclose(output_file);
00496 
00497 #ifdef PROGRESS_REPORT
00498   end_progress_monitor((j_common_ptr) &dstinfo);
00499 #endif
00500 
00501   /* All done. */
00502   exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS);
00503   return 0;                 /* suppress no-return-value warnings */
00504 }