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