ref: bf5dc91f8d7bc2035effd18290c523050fa1b2cd
dir: /code/jpeg-6/jpegtran.c/
/* * jpegtran.c * * Copyright (C) 1995, Thomas G. Lane. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file contains a command-line user interface for JPEG transcoding. * It is very similar to cjpeg.c, but provides lossless transcoding between * different JPEG file formats. */ #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ #include "jversion.h" /* for version message */ #ifdef USE_CCOMMAND /* command-line reader for Macintosh */ #ifdef __MWERKS__ #include <SIOUX.h> /* Metrowerks declares it here */ #endif #ifdef THINK_C #include <console.h> /* Think declares it here */ #endif #endif /* * Argument-parsing code. * The switch parser is designed to be useful with DOS-style command line * syntax, ie, intermixed switches and file names, where only the switches * to the left of a given file name affect processing of that file. * The main program in this file doesn't actually use this capability... */ static const char * progname; /* program name for error messages */ static char * outfilename; /* for -outfile switch */ LOCAL void usage (void) /* complain about bad command line */ { fprintf(stderr, "usage: %s [switches] ", progname); #ifdef TWO_FILE_COMMANDLINE fprintf(stderr, "inputfile outputfile\n"); #else fprintf(stderr, "[inputfile]\n"); #endif fprintf(stderr, "Switches (names may be abbreviated):\n"); #ifdef ENTROPY_OPT_SUPPORTED fprintf(stderr, " -optimize Optimize Huffman table (smaller file, but slow compression)\n"); #endif #ifdef C_PROGRESSIVE_SUPPORTED fprintf(stderr, " -progressive Create progressive JPEG file\n"); #endif fprintf(stderr, "Switches for advanced users:\n"); fprintf(stderr, " -restart N Set restart interval in rows, or in blocks with B\n"); fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n"); fprintf(stderr, " -outfile name Specify name for output file\n"); fprintf(stderr, " -verbose or -debug Emit debug output\n"); fprintf(stderr, "Switches for wizards:\n"); #ifdef C_ARITH_CODING_SUPPORTED fprintf(stderr, " -arithmetic Use arithmetic coding\n"); #endif #ifdef C_MULTISCAN_FILES_SUPPORTED fprintf(stderr, " -scans file Create multi-scan JPEG per script file\n"); #endif exit(EXIT_FAILURE); } LOCAL int parse_switches (j_compress_ptr cinfo, int argc, char **argv, int last_file_arg_seen, boolean for_real) /* Parse optional switches. * Returns argv[] index of first file-name argument (== argc if none). * Any file names with indexes <= last_file_arg_seen are ignored; * they have presumably been processed in a previous iteration. * (Pass 0 for last_file_arg_seen on the first or only iteration.) * for_real is FALSE on the first (dummy) pass; we may skip any expensive * processing. */ { int argn; char * arg; boolean simple_progressive; char * scansarg = NULL; /* saves -scans parm if any */ /* Set up default JPEG parameters. */ simple_progressive = FALSE; outfilename = NULL; cinfo->err->trace_level = 0; /* Scan command line options, adjust parameters */ for (argn = 1; argn < argc; argn++) { arg = argv[argn]; if (*arg != '-') { /* Not a switch, must be a file name argument */ if (argn <= last_file_arg_seen) { outfilename = NULL; /* -outfile applies to just one input file */ continue; /* ignore this name if previously processed */ } break; /* else done parsing switches */ } arg++; /* advance past switch marker character */ if (keymatch(arg, "arithmetic", 1)) { /* Use arithmetic coding. */ #ifdef C_ARITH_CODING_SUPPORTED cinfo->arith_code = TRUE; #else fprintf(stderr, "%s: sorry, arithmetic coding not supported\n", progname); exit(EXIT_FAILURE); #endif } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) { /* Enable debug printouts. */ /* On first -d, print version identification */ static boolean printed_version = FALSE; if (! printed_version) { fprintf(stderr, "Independent JPEG Group's JPEGTRAN, version %s\n%s\n", JVERSION, JCOPYRIGHT); printed_version = TRUE; } cinfo->err->trace_level++; } else if (keymatch(arg, "maxmemory", 3)) { /* Maximum memory in Kb (or Mb with 'm'). */ long lval; char ch = 'x'; if (++argn >= argc) /* advance to next argument */ usage(); if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) usage(); if (ch == 'm' || ch == 'M') lval *= 1000L; cinfo->mem->max_memory_to_use = lval * 1000L; } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) { /* Enable entropy parm optimization. */ #ifdef ENTROPY_OPT_SUPPORTED cinfo->optimize_coding = TRUE; #else fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n", progname); exit(EXIT_FAILURE); #endif } else if (keymatch(arg, "outfile", 4)) { /* Set output file name. */ if (++argn >= argc) /* advance to next argument */ usage(); outfilename = argv[argn]; /* save it away for later use */ } else if (keymatch(arg, "progressive", 1)) { /* Select simple progressive mode. */ #ifdef C_PROGRESSIVE_SUPPORTED simple_progressive = TRUE; /* We must postpone execution until num_components is known. */ #else fprintf(stderr, "%s: sorry, progressive output was not compiled\n", progname); exit(EXIT_FAILURE); #endif } else if (keymatch(arg, "restart", 1)) { /* Restart interval in MCU rows (or in MCUs with 'b'). */ long lval; char ch = 'x'; if (++argn >= argc) /* advance to next argument */ usage(); if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) usage(); if (lval < 0 || lval > 65535L) usage(); if (ch == 'b' || ch == 'B') { cinfo->restart_interval = (unsigned int) lval; cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */ } else { cinfo->restart_in_rows = (int) lval; /* restart_interval will be computed during startup */ } } else if (keymatch(arg, "scans", 2)) { /* Set scan script. */ #ifdef C_MULTISCAN_FILES_SUPPORTED if (++argn >= argc) /* advance to next argument */ usage(); scansarg = argv[argn]; /* We must postpone reading the file in case -progressive appears. */ #else fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n", progname); exit(EXIT_FAILURE); #endif } else { usage(); /* bogus switch */ } } /* Post-switch-scanning cleanup */ if (for_real) { #ifdef C_PROGRESSIVE_SUPPORTED if (simple_progressive) /* process -progressive; -scans can override */ jpeg_simple_progression(cinfo); #endif #ifdef C_MULTISCAN_FILES_SUPPORTED if (scansarg != NULL) /* process -scans if it was present */ if (! read_scan_script(cinfo, scansarg)) usage(); #endif } return argn; /* return index of next arg (file name) */ } /* * The main program. */ GLOBAL int main (int argc, char **argv) { struct jpeg_decompress_struct srcinfo; struct jpeg_compress_struct dstinfo; struct jpeg_error_mgr jsrcerr, jdsterr; #ifdef PROGRESS_REPORT struct cdjpeg_progress_mgr progress; #endif jvirt_barray_ptr * coef_arrays; int file_index; FILE * input_file; FILE * output_file; /* On Mac, fetch a command line. */ #ifdef USE_CCOMMAND argc = ccommand(&argv); #endif progname = argv[0]; if (progname == NULL || progname[0] == 0) progname = "jpegtran"; /* in case C library doesn't provide it */ /* Initialize the JPEG decompression object with default error handling. */ srcinfo.err = jpeg_std_error(&jsrcerr); jpeg_create_decompress(&srcinfo); /* Initialize the JPEG compression object with default error handling. */ dstinfo.err = jpeg_std_error(&jdsterr); jpeg_create_compress(&dstinfo); /* Now safe to enable signal catcher. * Note: we assume only the decompression object will have virtual arrays. */ #ifdef NEED_SIGNAL_CATCHER enable_signal_catcher((j_common_ptr) &srcinfo); #endif /* Scan command line to find file names. * It is convenient to use just one switch-parsing routine, but the switch * values read here are ignored; we will rescan the switches after opening * the input file. */ file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE); jsrcerr.trace_level = jdsterr.trace_level; #ifdef TWO_FILE_COMMANDLINE /* Must have either -outfile switch or explicit output file name */ if (outfilename == NULL) { if (file_index != argc-2) { fprintf(stderr, "%s: must name one input and one output file\n", progname); usage(); } outfilename = argv[file_index+1]; } else { if (file_index != argc-1) { fprintf(stderr, "%s: must name one input and one output file\n", progname); usage(); } } #else /* Unix style: expect zero or one file name */ if (file_index < argc-1) { fprintf(stderr, "%s: only one input file\n", progname); usage(); } #endif /* TWO_FILE_COMMANDLINE */ /* Open the input file. */ if (file_index < argc) { if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); exit(EXIT_FAILURE); } } else { /* default input file is stdin */ input_file = read_stdin(); } /* Open the output file. */ if (outfilename != NULL) { if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s\n", progname, outfilename); exit(EXIT_FAILURE); } } else { /* default output file is stdout */ output_file = write_stdout(); } #ifdef PROGRESS_REPORT start_progress_monitor((j_common_ptr) &dstinfo, &progress); #endif /* Specify data source for decompression */ jpeg_stdio_src(&srcinfo, input_file); /* Read file header */ (void) jpeg_read_header(&srcinfo, TRUE); /* Read source file as DCT coefficients */ coef_arrays = jpeg_read_coefficients(&srcinfo); /* Initialize destination compression parameters from source values */ jpeg_copy_critical_parameters(&srcinfo, &dstinfo); /* Adjust default compression parameters by re-parsing the options */ file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE); /* Specify data destination for compression */ jpeg_stdio_dest(&dstinfo, output_file); /* Start compressor */ jpeg_write_coefficients(&dstinfo, coef_arrays); /* ought to copy source comments here... */ /* Finish compression and release memory */ jpeg_finish_compress(&dstinfo); jpeg_destroy_compress(&dstinfo); (void) jpeg_finish_decompress(&srcinfo); jpeg_destroy_decompress(&srcinfo); /* Close files, if we opened them */ if (input_file != stdin) fclose(input_file); if (output_file != stdout) fclose(output_file); #ifdef PROGRESS_REPORT end_progress_monitor((j_common_ptr) &dstinfo); #endif /* All done. */ exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS); return 0; /* suppress no-return-value warnings */ }