blob: 4f76ae78fde619681004254fe77a5ea60852152b [file] [log] [blame]
Thomas G. Lanebc79e061995-08-02 00:00:00 +00001/*
2 * jpegtran.c
3 *
Guido Vollbeding989630f2010-01-10 00:00:00 +00004 * Copyright (C) 1995-2009, Thomas G. Lane, Guido Vollbeding.
Thomas G. Lanebc79e061995-08-02 00:00:00 +00005 * 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.
Guido Vollbeding989630f2010-01-10 00:00:00 +00009 * It is very similar to cjpeg.c, and partly to djpeg.c, but provides
10 * lossless transcoding between different JPEG file formats. It also
11 * provides some lossless and sort-of-lossless transformations of JPEG data.
Thomas G. Lanebc79e061995-08-02 00:00:00 +000012 */
13
14#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
Thomas G. Lane5ead57a1998-03-27 00:00:00 +000015#include "transupp.h" /* Support routines for jpegtran */
Thomas G. Lanebc79e061995-08-02 00:00:00 +000016#include "jversion.h" /* for version message */
17
18#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
19#ifdef __MWERKS__
Thomas G. Lane489583f1996-02-07 00:00:00 +000020#include <SIOUX.h> /* Metrowerks needs this */
21#include <console.h> /* ... and this */
Thomas G. Lanebc79e061995-08-02 00:00:00 +000022#endif
23#ifdef THINK_C
24#include <console.h> /* Think declares it here */
25#endif
26#endif
27
28
29/*
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...
35 */
36
37
38static const char * progname; /* program name for error messages */
39static char * outfilename; /* for -outfile switch */
Guido Vollbeding989630f2010-01-10 00:00:00 +000040static char * scaleoption; /* -scale switch */
Thomas G. Lane5ead57a1998-03-27 00:00:00 +000041static JCOPY_OPTION copyoption; /* -copy switch */
42static jpeg_transform_info transformoption; /* image transformation options */
Thomas G. Lanebc79e061995-08-02 00:00:00 +000043
44
Thomas G. Lane489583f1996-02-07 00:00:00 +000045LOCAL(void)
Thomas G. Lanebc79e061995-08-02 00:00:00 +000046usage (void)
47/* complain about bad command line */
48{
49 fprintf(stderr, "usage: %s [switches] ", progname);
50#ifdef TWO_FILE_COMMANDLINE
51 fprintf(stderr, "inputfile outputfile\n");
52#else
53 fprintf(stderr, "[inputfile]\n");
54#endif
55
56 fprintf(stderr, "Switches (names may be abbreviated):\n");
Thomas G. Lane5ead57a1998-03-27 00:00:00 +000057 fprintf(stderr, " -copy none Copy no extra markers from source file\n");
58 fprintf(stderr, " -copy comments Copy only comment markers (default)\n");
59 fprintf(stderr, " -copy all Copy all extra markers\n");
Thomas G. Lanebc79e061995-08-02 00:00:00 +000060#ifdef ENTROPY_OPT_SUPPORTED
61 fprintf(stderr, " -optimize Optimize Huffman table (smaller file, but slow compression)\n");
62#endif
63#ifdef C_PROGRESSIVE_SUPPORTED
64 fprintf(stderr, " -progressive Create progressive JPEG file\n");
65#endif
Thomas G. Lane5ead57a1998-03-27 00:00:00 +000066#if TRANSFORMS_SUPPORTED
67 fprintf(stderr, "Switches for modifying the image:\n");
Guido Vollbeding5996a252009-06-27 00:00:00 +000068 fprintf(stderr, " -crop WxH+X+Y Crop to a rectangular subarea\n");
Thomas G. Lane5ead57a1998-03-27 00:00:00 +000069 fprintf(stderr, " -grayscale Reduce to grayscale (omit color data)\n");
70 fprintf(stderr, " -flip [horizontal|vertical] Mirror image (left-right or top-bottom)\n");
Guido Vollbeding5996a252009-06-27 00:00:00 +000071 fprintf(stderr, " -perfect Fail if there is non-transformable edge blocks\n");
Thomas G. Lane5ead57a1998-03-27 00:00:00 +000072 fprintf(stderr, " -rotate [90|180|270] Rotate image (degrees clockwise)\n");
Guido Vollbeding989630f2010-01-10 00:00:00 +000073 fprintf(stderr, " -scale M/N Scale output image by fraction M/N, eg, 1/8\n");
Thomas G. Lane5ead57a1998-03-27 00:00:00 +000074 fprintf(stderr, " -transpose Transpose image\n");
75 fprintf(stderr, " -transverse Transverse transpose image\n");
76 fprintf(stderr, " -trim Drop non-transformable edge blocks\n");
77#endif /* TRANSFORMS_SUPPORTED */
Thomas G. Lanebc79e061995-08-02 00:00:00 +000078 fprintf(stderr, "Switches for advanced users:\n");
79 fprintf(stderr, " -restart N Set restart interval in rows, or in blocks with B\n");
80 fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n");
81 fprintf(stderr, " -outfile name Specify name for output file\n");
82 fprintf(stderr, " -verbose or -debug Emit debug output\n");
83 fprintf(stderr, "Switches for wizards:\n");
84#ifdef C_ARITH_CODING_SUPPORTED
85 fprintf(stderr, " -arithmetic Use arithmetic coding\n");
86#endif
87#ifdef C_MULTISCAN_FILES_SUPPORTED
88 fprintf(stderr, " -scans file Create multi-scan JPEG per script file\n");
89#endif
90 exit(EXIT_FAILURE);
91}
92
93
Thomas G. Lane5ead57a1998-03-27 00:00:00 +000094LOCAL(void)
95select_transform (JXFORM_CODE transform)
96/* Silly little routine to detect multiple transform options,
97 * which we can't handle.
98 */
99{
100#if TRANSFORMS_SUPPORTED
101 if (transformoption.transform == JXFORM_NONE ||
102 transformoption.transform == transform) {
103 transformoption.transform = transform;
104 } else {
105 fprintf(stderr, "%s: can only do one image transformation at a time\n",
106 progname);
107 usage();
108 }
109#else
110 fprintf(stderr, "%s: sorry, image transformation was not compiled\n",
111 progname);
112 exit(EXIT_FAILURE);
113#endif
114}
115
116
Thomas G. Lane489583f1996-02-07 00:00:00 +0000117LOCAL(int)
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000118parse_switches (j_compress_ptr cinfo, int argc, char **argv,
119 int last_file_arg_seen, boolean for_real)
120/* Parse optional switches.
121 * Returns argv[] index of first file-name argument (== argc if none).
122 * Any file names with indexes <= last_file_arg_seen are ignored;
123 * they have presumably been processed in a previous iteration.
124 * (Pass 0 for last_file_arg_seen on the first or only iteration.)
125 * for_real is FALSE on the first (dummy) pass; we may skip any expensive
126 * processing.
127 */
128{
129 int argn;
130 char * arg;
131 boolean simple_progressive;
132 char * scansarg = NULL; /* saves -scans parm if any */
133
134 /* Set up default JPEG parameters. */
135 simple_progressive = FALSE;
136 outfilename = NULL;
Guido Vollbeding989630f2010-01-10 00:00:00 +0000137 scaleoption = NULL;
Thomas G. Lane5ead57a1998-03-27 00:00:00 +0000138 copyoption = JCOPYOPT_DEFAULT;
139 transformoption.transform = JXFORM_NONE;
Guido Vollbeding5996a252009-06-27 00:00:00 +0000140 transformoption.perfect = FALSE;
Guido Vollbeding989630f2010-01-10 00:00:00 +0000141 transformoption.trim = FALSE;
Thomas G. Lane5ead57a1998-03-27 00:00:00 +0000142 transformoption.force_grayscale = FALSE;
Guido Vollbeding5996a252009-06-27 00:00:00 +0000143 transformoption.crop = FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000144 cinfo->err->trace_level = 0;
145
146 /* Scan command line options, adjust parameters */
147
148 for (argn = 1; argn < argc; argn++) {
149 arg = argv[argn];
150 if (*arg != '-') {
151 /* Not a switch, must be a file name argument */
152 if (argn <= last_file_arg_seen) {
153 outfilename = NULL; /* -outfile applies to just one input file */
154 continue; /* ignore this name if previously processed */
155 }
156 break; /* else done parsing switches */
157 }
158 arg++; /* advance past switch marker character */
159
160 if (keymatch(arg, "arithmetic", 1)) {
161 /* Use arithmetic coding. */
162#ifdef C_ARITH_CODING_SUPPORTED
163 cinfo->arith_code = TRUE;
164#else
165 fprintf(stderr, "%s: sorry, arithmetic coding not supported\n",
166 progname);
167 exit(EXIT_FAILURE);
168#endif
169
Guido Vollbeding5996a252009-06-27 00:00:00 +0000170 } else if (keymatch(arg, "copy", 2)) {
Thomas G. Lane5ead57a1998-03-27 00:00:00 +0000171 /* Select which extra markers to copy. */
172 if (++argn >= argc) /* advance to next argument */
173 usage();
174 if (keymatch(argv[argn], "none", 1)) {
175 copyoption = JCOPYOPT_NONE;
176 } else if (keymatch(argv[argn], "comments", 1)) {
177 copyoption = JCOPYOPT_COMMENTS;
178 } else if (keymatch(argv[argn], "all", 1)) {
179 copyoption = JCOPYOPT_ALL;
180 } else
181 usage();
182
Guido Vollbeding5996a252009-06-27 00:00:00 +0000183 } else if (keymatch(arg, "crop", 2)) {
184 /* Perform lossless cropping. */
185#if TRANSFORMS_SUPPORTED
186 if (++argn >= argc) /* advance to next argument */
187 usage();
188 if (! jtransform_parse_crop_spec(&transformoption, argv[argn])) {
189 fprintf(stderr, "%s: bogus -crop argument '%s'\n",
190 progname, argv[argn]);
191 exit(EXIT_FAILURE);
192 }
193#else
194 select_transform(JXFORM_NONE); /* force an error */
195#endif
196
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000197 } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
198 /* Enable debug printouts. */
199 /* On first -d, print version identification */
200 static boolean printed_version = FALSE;
201
202 if (! printed_version) {
203 fprintf(stderr, "Independent JPEG Group's JPEGTRAN, version %s\n%s\n",
204 JVERSION, JCOPYRIGHT);
205 printed_version = TRUE;
206 }
207 cinfo->err->trace_level++;
208
Thomas G. Lane5ead57a1998-03-27 00:00:00 +0000209 } else if (keymatch(arg, "flip", 1)) {
210 /* Mirror left-right or top-bottom. */
211 if (++argn >= argc) /* advance to next argument */
212 usage();
213 if (keymatch(argv[argn], "horizontal", 1))
214 select_transform(JXFORM_FLIP_H);
215 else if (keymatch(argv[argn], "vertical", 1))
216 select_transform(JXFORM_FLIP_V);
217 else
218 usage();
219
220 } else if (keymatch(arg, "grayscale", 1) || keymatch(arg, "greyscale",1)) {
221 /* Force to grayscale. */
222#if TRANSFORMS_SUPPORTED
223 transformoption.force_grayscale = TRUE;
224#else
225 select_transform(JXFORM_NONE); /* force an error */
226#endif
227
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000228 } else if (keymatch(arg, "maxmemory", 3)) {
229 /* Maximum memory in Kb (or Mb with 'm'). */
230 long lval;
231 char ch = 'x';
232
233 if (++argn >= argc) /* advance to next argument */
234 usage();
235 if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
236 usage();
237 if (ch == 'm' || ch == 'M')
238 lval *= 1000L;
239 cinfo->mem->max_memory_to_use = lval * 1000L;
240
241 } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) {
242 /* Enable entropy parm optimization. */
243#ifdef ENTROPY_OPT_SUPPORTED
244 cinfo->optimize_coding = TRUE;
245#else
246 fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n",
247 progname);
248 exit(EXIT_FAILURE);
249#endif
250
251 } else if (keymatch(arg, "outfile", 4)) {
252 /* Set output file name. */
253 if (++argn >= argc) /* advance to next argument */
254 usage();
255 outfilename = argv[argn]; /* save it away for later use */
256
Guido Vollbeding5996a252009-06-27 00:00:00 +0000257 } else if (keymatch(arg, "perfect", 2)) {
258 /* Fail if there is any partial edge MCUs that the transform can't
259 * handle. */
260 transformoption.perfect = TRUE;
261
262 } else if (keymatch(arg, "progressive", 2)) {
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000263 /* Select simple progressive mode. */
264#ifdef C_PROGRESSIVE_SUPPORTED
265 simple_progressive = TRUE;
266 /* We must postpone execution until num_components is known. */
267#else
268 fprintf(stderr, "%s: sorry, progressive output was not compiled\n",
269 progname);
270 exit(EXIT_FAILURE);
271#endif
272
273 } else if (keymatch(arg, "restart", 1)) {
274 /* Restart interval in MCU rows (or in MCUs with 'b'). */
275 long lval;
276 char ch = 'x';
277
278 if (++argn >= argc) /* advance to next argument */
279 usage();
280 if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
281 usage();
282 if (lval < 0 || lval > 65535L)
283 usage();
284 if (ch == 'b' || ch == 'B') {
285 cinfo->restart_interval = (unsigned int) lval;
286 cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */
287 } else {
288 cinfo->restart_in_rows = (int) lval;
289 /* restart_interval will be computed during startup */
290 }
291
Thomas G. Lane5ead57a1998-03-27 00:00:00 +0000292 } else if (keymatch(arg, "rotate", 2)) {
293 /* Rotate 90, 180, or 270 degrees (measured clockwise). */
294 if (++argn >= argc) /* advance to next argument */
295 usage();
296 if (keymatch(argv[argn], "90", 2))
297 select_transform(JXFORM_ROT_90);
298 else if (keymatch(argv[argn], "180", 3))
299 select_transform(JXFORM_ROT_180);
300 else if (keymatch(argv[argn], "270", 3))
301 select_transform(JXFORM_ROT_270);
302 else
303 usage();
304
Guido Vollbeding989630f2010-01-10 00:00:00 +0000305 } else if (keymatch(arg, "scale", 4)) {
306 /* Scale the output image by a fraction M/N. */
307 if (++argn >= argc) /* advance to next argument */
308 usage();
309 scaleoption = argv[argn];
310 /* We must postpone processing until decompression startup. */
311
Thomas G. Lane5ead57a1998-03-27 00:00:00 +0000312 } else if (keymatch(arg, "scans", 1)) {
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000313 /* Set scan script. */
314#ifdef C_MULTISCAN_FILES_SUPPORTED
315 if (++argn >= argc) /* advance to next argument */
316 usage();
317 scansarg = argv[argn];
318 /* We must postpone reading the file in case -progressive appears. */
319#else
320 fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n",
321 progname);
322 exit(EXIT_FAILURE);
323#endif
324
Thomas G. Lane5ead57a1998-03-27 00:00:00 +0000325 } else if (keymatch(arg, "transpose", 1)) {
326 /* Transpose (across UL-to-LR axis). */
327 select_transform(JXFORM_TRANSPOSE);
328
329 } else if (keymatch(arg, "transverse", 6)) {
330 /* Transverse transpose (across UR-to-LL axis). */
331 select_transform(JXFORM_TRANSVERSE);
332
333 } else if (keymatch(arg, "trim", 3)) {
334 /* Trim off any partial edge MCUs that the transform can't handle. */
335 transformoption.trim = TRUE;
336
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000337 } else {
338 usage(); /* bogus switch */
339 }
340 }
341
342 /* Post-switch-scanning cleanup */
343
344 if (for_real) {
345
346#ifdef C_PROGRESSIVE_SUPPORTED
347 if (simple_progressive) /* process -progressive; -scans can override */
348 jpeg_simple_progression(cinfo);
349#endif
350
351#ifdef C_MULTISCAN_FILES_SUPPORTED
352 if (scansarg != NULL) /* process -scans if it was present */
353 if (! read_scan_script(cinfo, scansarg))
354 usage();
355#endif
356 }
357
358 return argn; /* return index of next arg (file name) */
359}
360
361
362/*
363 * The main program.
364 */
365
Thomas G. Lane489583f1996-02-07 00:00:00 +0000366int
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000367main (int argc, char **argv)
368{
369 struct jpeg_decompress_struct srcinfo;
370 struct jpeg_compress_struct dstinfo;
371 struct jpeg_error_mgr jsrcerr, jdsterr;
372#ifdef PROGRESS_REPORT
373 struct cdjpeg_progress_mgr progress;
374#endif
Thomas G. Lane5ead57a1998-03-27 00:00:00 +0000375 jvirt_barray_ptr * src_coef_arrays;
376 jvirt_barray_ptr * dst_coef_arrays;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000377 int file_index;
Guido Vollbeding5996a252009-06-27 00:00:00 +0000378 /* We assume all-in-memory processing and can therefore use only a
379 * single file pointer for sequential input and output operation.
380 */
381 FILE * fp;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000382
383 /* On Mac, fetch a command line. */
384#ifdef USE_CCOMMAND
385 argc = ccommand(&argv);
386#endif
387
388 progname = argv[0];
389 if (progname == NULL || progname[0] == 0)
390 progname = "jpegtran"; /* in case C library doesn't provide it */
391
392 /* Initialize the JPEG decompression object with default error handling. */
393 srcinfo.err = jpeg_std_error(&jsrcerr);
394 jpeg_create_decompress(&srcinfo);
395 /* Initialize the JPEG compression object with default error handling. */
396 dstinfo.err = jpeg_std_error(&jdsterr);
397 jpeg_create_compress(&dstinfo);
398
399 /* Now safe to enable signal catcher.
400 * Note: we assume only the decompression object will have virtual arrays.
401 */
402#ifdef NEED_SIGNAL_CATCHER
403 enable_signal_catcher((j_common_ptr) &srcinfo);
404#endif
405
406 /* Scan command line to find file names.
407 * It is convenient to use just one switch-parsing routine, but the switch
Thomas G. Lane5ead57a1998-03-27 00:00:00 +0000408 * values read here are mostly ignored; we will rescan the switches after
409 * opening the input file. Also note that most of the switches affect the
410 * destination JPEG object, so we parse into that and then copy over what
411 * needs to affects the source too.
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000412 */
413
414 file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE);
415 jsrcerr.trace_level = jdsterr.trace_level;
Thomas G. Lane489583f1996-02-07 00:00:00 +0000416 srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000417
418#ifdef TWO_FILE_COMMANDLINE
419 /* Must have either -outfile switch or explicit output file name */
420 if (outfilename == NULL) {
421 if (file_index != argc-2) {
422 fprintf(stderr, "%s: must name one input and one output file\n",
423 progname);
424 usage();
425 }
426 outfilename = argv[file_index+1];
427 } else {
428 if (file_index != argc-1) {
429 fprintf(stderr, "%s: must name one input and one output file\n",
430 progname);
431 usage();
432 }
433 }
434#else
435 /* Unix style: expect zero or one file name */
436 if (file_index < argc-1) {
437 fprintf(stderr, "%s: only one input file\n", progname);
438 usage();
439 }
440#endif /* TWO_FILE_COMMANDLINE */
441
442 /* Open the input file. */
443 if (file_index < argc) {
Guido Vollbeding5996a252009-06-27 00:00:00 +0000444 if ((fp = fopen(argv[file_index], READ_BINARY)) == NULL) {
445 fprintf(stderr, "%s: can't open %s for reading\n", progname, argv[file_index]);
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000446 exit(EXIT_FAILURE);
447 }
448 } else {
449 /* default input file is stdin */
Guido Vollbeding5996a252009-06-27 00:00:00 +0000450 fp = read_stdin();
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000451 }
452
453#ifdef PROGRESS_REPORT
454 start_progress_monitor((j_common_ptr) &dstinfo, &progress);
455#endif
456
457 /* Specify data source for decompression */
Guido Vollbeding5996a252009-06-27 00:00:00 +0000458 jpeg_stdio_src(&srcinfo, fp);
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000459
Thomas G. Lane5ead57a1998-03-27 00:00:00 +0000460 /* Enable saving of extra markers that we want to copy */
461 jcopy_markers_setup(&srcinfo, copyoption);
462
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000463 /* Read file header */
464 (void) jpeg_read_header(&srcinfo, TRUE);
465
Guido Vollbeding989630f2010-01-10 00:00:00 +0000466 /* Adjust default decompression parameters */
467 if (scaleoption != NULL)
468 if (sscanf(scaleoption, "%d/%d",
469 &srcinfo.scale_num, &srcinfo.scale_denom) < 1)
470 usage();
471
Thomas G. Lane5ead57a1998-03-27 00:00:00 +0000472 /* Any space needed by a transform option must be requested before
473 * jpeg_read_coefficients so that memory allocation will be done right.
474 */
475#if TRANSFORMS_SUPPORTED
Guido Vollbeding989630f2010-01-10 00:00:00 +0000476 /* Fail right away if -perfect is given and transformation is not perfect.
Guido Vollbeding5996a252009-06-27 00:00:00 +0000477 */
Guido Vollbeding989630f2010-01-10 00:00:00 +0000478 if (!jtransform_request_workspace(&srcinfo, &transformoption)) {
Guido Vollbeding5996a252009-06-27 00:00:00 +0000479 fprintf(stderr, "%s: transformation is not perfect\n", progname);
480 exit(EXIT_FAILURE);
481 }
Thomas G. Lane5ead57a1998-03-27 00:00:00 +0000482#endif
483
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000484 /* Read source file as DCT coefficients */
Thomas G. Lane5ead57a1998-03-27 00:00:00 +0000485 src_coef_arrays = jpeg_read_coefficients(&srcinfo);
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000486
487 /* Initialize destination compression parameters from source values */
488 jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
489
Thomas G. Lane5ead57a1998-03-27 00:00:00 +0000490 /* Adjust destination parameters if required by transform options;
491 * also find out which set of coefficient arrays will hold the output.
492 */
493#if TRANSFORMS_SUPPORTED
494 dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo,
495 src_coef_arrays,
496 &transformoption);
497#else
498 dst_coef_arrays = src_coef_arrays;
499#endif
500
Guido Vollbeding5996a252009-06-27 00:00:00 +0000501 /* Close input file, if we opened it.
502 * Note: we assume that jpeg_read_coefficients consumed all input
503 * until JPEG_REACHED_EOI, and that jpeg_finish_decompress will
504 * only consume more while (! cinfo->inputctl->eoi_reached).
505 * We cannot call jpeg_finish_decompress here since we still need the
506 * virtual arrays allocated from the source object for processing.
507 */
508 if (fp != stdin)
509 fclose(fp);
510
511 /* Open the output file. */
512 if (outfilename != NULL) {
513 if ((fp = fopen(outfilename, WRITE_BINARY)) == NULL) {
514 fprintf(stderr, "%s: can't open %s for writing\n", progname, outfilename);
515 exit(EXIT_FAILURE);
516 }
517 } else {
518 /* default output file is stdout */
519 fp = write_stdout();
520 }
521
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000522 /* Adjust default compression parameters by re-parsing the options */
523 file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE);
524
525 /* Specify data destination for compression */
Guido Vollbeding5996a252009-06-27 00:00:00 +0000526 jpeg_stdio_dest(&dstinfo, fp);
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000527
Thomas G. Lane5ead57a1998-03-27 00:00:00 +0000528 /* Start compressor (note no image data is actually written here) */
529 jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000530
Thomas G. Lane5ead57a1998-03-27 00:00:00 +0000531 /* Copy to the output file any extra markers that we want to preserve */
532 jcopy_markers_execute(&srcinfo, &dstinfo, copyoption);
533
534 /* Execute image transformation, if any */
535#if TRANSFORMS_SUPPORTED
536 jtransform_execute_transformation(&srcinfo, &dstinfo,
537 src_coef_arrays,
538 &transformoption);
539#endif
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000540
541 /* Finish compression and release memory */
542 jpeg_finish_compress(&dstinfo);
543 jpeg_destroy_compress(&dstinfo);
544 (void) jpeg_finish_decompress(&srcinfo);
545 jpeg_destroy_decompress(&srcinfo);
546
Guido Vollbeding5996a252009-06-27 00:00:00 +0000547 /* Close output file, if we opened it */
548 if (fp != stdout)
549 fclose(fp);
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000550
551#ifdef PROGRESS_REPORT
552 end_progress_monitor((j_common_ptr) &dstinfo);
553#endif
554
555 /* All done. */
556 exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS);
557 return 0; /* suppress no-return-value warnings */
558}