blob: 925ca8a8d71aaf90ee726bfec9478b0d3009cc54 [file] [log] [blame]
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001/*
2 * djpeg.c
3 *
noel@chromium.org3395bcc2014-04-14 06:56:00 +00004 * This file was part of the Independent JPEG Group's software:
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00005 * Copyright (C) 1991-1997, Thomas G. Lane.
noel@chromium.org3395bcc2014-04-14 06:56:00 +00006 * libjpeg-turbo Modifications:
Aaron Gablec9c87552015-08-03 09:34:32 -07007 * Copyright (C) 2010-2011, 2013-2015, D. R. Commander.
8 * Copyright (C) 2015, Google, Inc.
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00009 * For conditions of distribution and use, see the accompanying README file.
10 *
11 * This file contains a command-line user interface for the JPEG decompressor.
12 * It should work on any system with Unix- or MS-DOS-style command lines.
13 *
14 * Two different command line styles are permitted, depending on the
15 * compile-time switch TWO_FILE_COMMANDLINE:
16 * djpeg [options] inputfile outputfile
17 * djpeg [options] [inputfile]
18 * In the second style, output is always to standard output, which you'd
19 * normally redirect to a file or pipe to some other program. Input is
20 * either from a named file or from standard input (typically redirected).
21 * The second style is convenient on Unix but is unhelpful on systems that
22 * don't support pipes. Also, you MUST use the first style if your system
23 * doesn't do binary I/O to stdin/stdout.
24 * To simplify script writing, the "-outfile" switch is provided. The syntax
25 * djpeg [options] -outfile outputfile inputfile
26 * works regardless of which command line style is used.
27 */
28
29#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
30#include "jversion.h" /* for version message */
hbono@chromium.org98626972011-08-03 03:13:08 +000031#include "config.h"
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000032
33#include <ctype.h> /* to declare isprint() */
34
35#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
36#ifdef __MWERKS__
37#include <SIOUX.h> /* Metrowerks needs this */
38#include <console.h> /* ... and this */
39#endif
40#ifdef THINK_C
41#include <console.h> /* Think declares it here */
42#endif
43#endif
44
45
46/* Create the add-on message string table. */
47
48#define JMESSAGE(code,string) string ,
49
50static const char * const cdjpeg_message_table[] = {
51#include "cderror.h"
52 NULL
53};
54
55
56/*
57 * This list defines the known output image formats
58 * (not all of which need be supported by a given version).
59 * You can change the default output format by defining DEFAULT_FMT;
60 * indeed, you had better do so if you undefine PPM_SUPPORTED.
61 */
62
63typedef enum {
64 FMT_BMP, /* BMP format (Windows flavor) */
65 FMT_GIF, /* GIF format */
66 FMT_OS2, /* BMP format (OS/2 flavor) */
67 FMT_PPM, /* PPM/PGM (PBMPLUS formats) */
68 FMT_RLE, /* RLE format */
69 FMT_TARGA, /* Targa format */
70 FMT_TIFF /* TIFF format */
71} IMAGE_FORMATS;
72
73#ifndef DEFAULT_FMT /* so can override from CFLAGS in Makefile */
74#define DEFAULT_FMT FMT_PPM
75#endif
76
77static IMAGE_FORMATS requested_fmt;
78
79
80/*
81 * Argument-parsing code.
82 * The switch parser is designed to be useful with DOS-style command line
83 * syntax, ie, intermixed switches and file names, where only the switches
84 * to the left of a given file name affect processing of that file.
85 * The main program in this file doesn't actually use this capability...
86 */
87
88
89static const char * progname; /* program name for error messages */
90static char * outfilename; /* for -outfile switch */
noel@chromium.org3395bcc2014-04-14 06:56:00 +000091boolean memsrc; /* for -memsrc switch */
Aaron Gablec9c87552015-08-03 09:34:32 -070092boolean strip, skip;
93JDIMENSION startY, endY;
noel@chromium.org3395bcc2014-04-14 06:56:00 +000094#define INPUT_BUF_SIZE 4096
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000095
96
97LOCAL(void)
98usage (void)
99/* complain about bad command line */
100{
101 fprintf(stderr, "usage: %s [switches] ", progname);
102#ifdef TWO_FILE_COMMANDLINE
103 fprintf(stderr, "inputfile outputfile\n");
104#else
105 fprintf(stderr, "[inputfile]\n");
106#endif
107
108 fprintf(stderr, "Switches (names may be abbreviated):\n");
109 fprintf(stderr, " -colors N Reduce image to no more than N colors\n");
110 fprintf(stderr, " -fast Fast, low-quality processing\n");
111 fprintf(stderr, " -grayscale Force grayscale output\n");
hbono@chromium.org98626972011-08-03 03:13:08 +0000112 fprintf(stderr, " -rgb Force RGB output\n");
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000113#ifdef IDCT_SCALING_SUPPORTED
114 fprintf(stderr, " -scale M/N Scale output image by fraction M/N, eg, 1/8\n");
115#endif
116#ifdef BMP_SUPPORTED
117 fprintf(stderr, " -bmp Select BMP output format (Windows style)%s\n",
118 (DEFAULT_FMT == FMT_BMP ? " (default)" : ""));
119#endif
120#ifdef GIF_SUPPORTED
121 fprintf(stderr, " -gif Select GIF output format%s\n",
122 (DEFAULT_FMT == FMT_GIF ? " (default)" : ""));
123#endif
124#ifdef BMP_SUPPORTED
125 fprintf(stderr, " -os2 Select BMP output format (OS/2 style)%s\n",
126 (DEFAULT_FMT == FMT_OS2 ? " (default)" : ""));
127#endif
128#ifdef PPM_SUPPORTED
129 fprintf(stderr, " -pnm Select PBMPLUS (PPM/PGM) output format%s\n",
130 (DEFAULT_FMT == FMT_PPM ? " (default)" : ""));
131#endif
132#ifdef RLE_SUPPORTED
133 fprintf(stderr, " -rle Select Utah RLE output format%s\n",
134 (DEFAULT_FMT == FMT_RLE ? " (default)" : ""));
135#endif
136#ifdef TARGA_SUPPORTED
137 fprintf(stderr, " -targa Select Targa output format%s\n",
138 (DEFAULT_FMT == FMT_TARGA ? " (default)" : ""));
139#endif
140 fprintf(stderr, "Switches for advanced users:\n");
141#ifdef DCT_ISLOW_SUPPORTED
142 fprintf(stderr, " -dct int Use integer DCT method%s\n",
143 (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : ""));
144#endif
145#ifdef DCT_IFAST_SUPPORTED
146 fprintf(stderr, " -dct fast Use fast integer DCT (less accurate)%s\n",
147 (JDCT_DEFAULT == JDCT_IFAST ? " (default)" : ""));
148#endif
149#ifdef DCT_FLOAT_SUPPORTED
150 fprintf(stderr, " -dct float Use floating-point DCT method%s\n",
151 (JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : ""));
152#endif
153 fprintf(stderr, " -dither fs Use F-S dithering (default)\n");
154 fprintf(stderr, " -dither none Don't use dithering in quantization\n");
155 fprintf(stderr, " -dither ordered Use ordered dither (medium speed, quality)\n");
156#ifdef QUANT_2PASS_SUPPORTED
157 fprintf(stderr, " -map FILE Map to colors used in named image file\n");
158#endif
159 fprintf(stderr, " -nosmooth Don't use high-quality upsampling\n");
160#ifdef QUANT_1PASS_SUPPORTED
161 fprintf(stderr, " -onepass Use 1-pass quantization (fast, low quality)\n");
162#endif
163 fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n");
164 fprintf(stderr, " -outfile name Specify name for output file\n");
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000165#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
166 fprintf(stderr, " -memsrc Load input file into memory before decompressing\n");
167#endif
168
Aaron Gablec9c87552015-08-03 09:34:32 -0700169 fprintf(stderr, " -skip Y0,Y1 Decode all rows except those between Y0 and Y1 (inclusive)\n");
170 fprintf(stderr, " -strip Y0,Y1 Decode only rows between Y0 and Y1 (inclusive)\n");
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000171 fprintf(stderr, " -verbose or -debug Emit debug output\n");
172 exit(EXIT_FAILURE);
173}
174
175
176LOCAL(int)
177parse_switches (j_decompress_ptr cinfo, int argc, char **argv,
178 int last_file_arg_seen, boolean for_real)
179/* Parse optional switches.
180 * Returns argv[] index of first file-name argument (== argc if none).
181 * Any file names with indexes <= last_file_arg_seen are ignored;
182 * they have presumably been processed in a previous iteration.
183 * (Pass 0 for last_file_arg_seen on the first or only iteration.)
184 * for_real is FALSE on the first (dummy) pass; we may skip any expensive
185 * processing.
186 */
187{
188 int argn;
189 char * arg;
190
191 /* Set up default JPEG parameters. */
192 requested_fmt = DEFAULT_FMT; /* set default output file format */
193 outfilename = NULL;
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000194 memsrc = FALSE;
Aaron Gablec9c87552015-08-03 09:34:32 -0700195 strip = FALSE;
196 skip = FALSE;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000197 cinfo->err->trace_level = 0;
198
199 /* Scan command line options, adjust parameters */
200
201 for (argn = 1; argn < argc; argn++) {
202 arg = argv[argn];
203 if (*arg != '-') {
204 /* Not a switch, must be a file name argument */
205 if (argn <= last_file_arg_seen) {
206 outfilename = NULL; /* -outfile applies to just one input file */
207 continue; /* ignore this name if previously processed */
208 }
209 break; /* else done parsing switches */
210 }
211 arg++; /* advance past switch marker character */
212
213 if (keymatch(arg, "bmp", 1)) {
214 /* BMP output format. */
215 requested_fmt = FMT_BMP;
216
217 } else if (keymatch(arg, "colors", 1) || keymatch(arg, "colours", 1) ||
218 keymatch(arg, "quantize", 1) || keymatch(arg, "quantise", 1)) {
219 /* Do color quantization. */
220 int val;
221
222 if (++argn >= argc) /* advance to next argument */
223 usage();
224 if (sscanf(argv[argn], "%d", &val) != 1)
225 usage();
226 cinfo->desired_number_of_colors = val;
227 cinfo->quantize_colors = TRUE;
228
229 } else if (keymatch(arg, "dct", 2)) {
230 /* Select IDCT algorithm. */
231 if (++argn >= argc) /* advance to next argument */
232 usage();
233 if (keymatch(argv[argn], "int", 1)) {
234 cinfo->dct_method = JDCT_ISLOW;
235 } else if (keymatch(argv[argn], "fast", 2)) {
236 cinfo->dct_method = JDCT_IFAST;
237 } else if (keymatch(argv[argn], "float", 2)) {
238 cinfo->dct_method = JDCT_FLOAT;
239 } else
240 usage();
241
242 } else if (keymatch(arg, "dither", 2)) {
243 /* Select dithering algorithm. */
244 if (++argn >= argc) /* advance to next argument */
245 usage();
246 if (keymatch(argv[argn], "fs", 2)) {
247 cinfo->dither_mode = JDITHER_FS;
248 } else if (keymatch(argv[argn], "none", 2)) {
249 cinfo->dither_mode = JDITHER_NONE;
250 } else if (keymatch(argv[argn], "ordered", 2)) {
251 cinfo->dither_mode = JDITHER_ORDERED;
252 } else
253 usage();
254
255 } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
256 /* Enable debug printouts. */
257 /* On first -d, print version identification */
258 static boolean printed_version = FALSE;
259
260 if (! printed_version) {
hbono@chromium.org98626972011-08-03 03:13:08 +0000261 fprintf(stderr, "%s version %s (build %s)\n",
262 PACKAGE_NAME, VERSION, BUILD);
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000263 fprintf(stderr, "%s\n\n", JCOPYRIGHT);
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000264 fprintf(stderr, "Emulating The Independent JPEG Group's software, version %s\n\n",
hbono@chromium.orgdf5ffdd2012-05-11 07:46:03 +0000265 JVERSION);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000266 printed_version = TRUE;
267 }
268 cinfo->err->trace_level++;
269
270 } else if (keymatch(arg, "fast", 1)) {
271 /* Select recommended processing options for quick-and-dirty output. */
272 cinfo->two_pass_quantize = FALSE;
273 cinfo->dither_mode = JDITHER_ORDERED;
274 if (! cinfo->quantize_colors) /* don't override an earlier -colors */
275 cinfo->desired_number_of_colors = 216;
276 cinfo->dct_method = JDCT_FASTEST;
277 cinfo->do_fancy_upsampling = FALSE;
278
279 } else if (keymatch(arg, "gif", 1)) {
280 /* GIF output format. */
281 requested_fmt = FMT_GIF;
282
283 } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) {
284 /* Force monochrome output. */
285 cinfo->out_color_space = JCS_GRAYSCALE;
286
hbono@chromium.org98626972011-08-03 03:13:08 +0000287 } else if (keymatch(arg, "rgb", 2)) {
288 /* Force RGB output. */
289 cinfo->out_color_space = JCS_RGB;
290
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000291 } else if (keymatch(arg, "map", 3)) {
292 /* Quantize to a color map taken from an input file. */
293 if (++argn >= argc) /* advance to next argument */
294 usage();
295 if (for_real) { /* too expensive to do twice! */
296#ifdef QUANT_2PASS_SUPPORTED /* otherwise can't quantize to supplied map */
297 FILE * mapfile;
298
299 if ((mapfile = fopen(argv[argn], READ_BINARY)) == NULL) {
300 fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
301 exit(EXIT_FAILURE);
302 }
303 read_color_map(cinfo, mapfile);
304 fclose(mapfile);
305 cinfo->quantize_colors = TRUE;
306#else
307 ERREXIT(cinfo, JERR_NOT_COMPILED);
308#endif
309 }
310
311 } else if (keymatch(arg, "maxmemory", 3)) {
312 /* Maximum memory in Kb (or Mb with 'm'). */
313 long lval;
314 char ch = 'x';
315
316 if (++argn >= argc) /* advance to next argument */
317 usage();
318 if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
319 usage();
320 if (ch == 'm' || ch == 'M')
321 lval *= 1000L;
322 cinfo->mem->max_memory_to_use = lval * 1000L;
323
324 } else if (keymatch(arg, "nosmooth", 3)) {
325 /* Suppress fancy upsampling */
326 cinfo->do_fancy_upsampling = FALSE;
327
328 } else if (keymatch(arg, "onepass", 3)) {
329 /* Use fast one-pass quantization. */
330 cinfo->two_pass_quantize = FALSE;
331
332 } else if (keymatch(arg, "os2", 3)) {
333 /* BMP output format (OS/2 flavor). */
334 requested_fmt = FMT_OS2;
335
336 } else if (keymatch(arg, "outfile", 4)) {
337 /* Set output file name. */
338 if (++argn >= argc) /* advance to next argument */
339 usage();
340 outfilename = argv[argn]; /* save it away for later use */
341
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000342 } else if (keymatch(arg, "memsrc", 2)) {
343 /* Use in-memory source manager */
344#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
345 memsrc = TRUE;
346#else
347 fprintf(stderr, "%s: sorry, in-memory source manager was not compiled in\n",
348 progname);
349 exit(EXIT_FAILURE);
350#endif
351
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000352 } else if (keymatch(arg, "pnm", 1) || keymatch(arg, "ppm", 1)) {
353 /* PPM/PGM output format. */
354 requested_fmt = FMT_PPM;
355
356 } else if (keymatch(arg, "rle", 1)) {
357 /* RLE output format. */
358 requested_fmt = FMT_RLE;
359
Aaron Gablec9c87552015-08-03 09:34:32 -0700360 } else if (keymatch(arg, "scale", 2)) {
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000361 /* Scale the output image by a fraction M/N. */
362 if (++argn >= argc) /* advance to next argument */
363 usage();
364 if (sscanf(argv[argn], "%d/%d",
365 &cinfo->scale_num, &cinfo->scale_denom) != 2)
366 usage();
367
Aaron Gablec9c87552015-08-03 09:34:32 -0700368 } else if (keymatch(arg, "strip", 2)) {
369 if (++argn >= argc)
370 usage();
371 if (sscanf(argv[argn], "%d,%d", &startY, &endY) != 2 || startY > endY)
372 usage();
373 strip = TRUE;
374
375 } else if (keymatch(arg, "skip", 2)) {
376 if (++argn >= argc)
377 usage();
378 if (sscanf(argv[argn], "%d,%d", &startY, &endY) != 2 || startY > endY)
379 usage();
380 skip = TRUE;
381
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000382 } else if (keymatch(arg, "targa", 1)) {
383 /* Targa output format. */
384 requested_fmt = FMT_TARGA;
385
386 } else {
387 usage(); /* bogus switch */
388 }
389 }
390
391 return argn; /* return index of next arg (file name) */
392}
393
394
395/*
396 * Marker processor for COM and interesting APPn markers.
397 * This replaces the library's built-in processor, which just skips the marker.
398 * We want to print out the marker as text, to the extent possible.
399 * Note this code relies on a non-suspending data source.
400 */
401
402LOCAL(unsigned int)
403jpeg_getc (j_decompress_ptr cinfo)
404/* Read next byte */
405{
406 struct jpeg_source_mgr * datasrc = cinfo->src;
407
408 if (datasrc->bytes_in_buffer == 0) {
409 if (! (*datasrc->fill_input_buffer) (cinfo))
410 ERREXIT(cinfo, JERR_CANT_SUSPEND);
411 }
412 datasrc->bytes_in_buffer--;
413 return GETJOCTET(*datasrc->next_input_byte++);
414}
415
416
417METHODDEF(boolean)
418print_text_marker (j_decompress_ptr cinfo)
419{
420 boolean traceit = (cinfo->err->trace_level >= 1);
421 INT32 length;
422 unsigned int ch;
423 unsigned int lastch = 0;
424
425 length = jpeg_getc(cinfo) << 8;
426 length += jpeg_getc(cinfo);
427 length -= 2; /* discount the length word itself */
428
429 if (traceit) {
430 if (cinfo->unread_marker == JPEG_COM)
431 fprintf(stderr, "Comment, length %ld:\n", (long) length);
432 else /* assume it is an APPn otherwise */
433 fprintf(stderr, "APP%d, length %ld:\n",
434 cinfo->unread_marker - JPEG_APP0, (long) length);
435 }
436
437 while (--length >= 0) {
438 ch = jpeg_getc(cinfo);
439 if (traceit) {
440 /* Emit the character in a readable form.
441 * Nonprintables are converted to \nnn form,
442 * while \ is converted to \\.
443 * Newlines in CR, CR/LF, or LF form will be printed as one newline.
444 */
445 if (ch == '\r') {
446 fprintf(stderr, "\n");
447 } else if (ch == '\n') {
448 if (lastch != '\r')
449 fprintf(stderr, "\n");
450 } else if (ch == '\\') {
451 fprintf(stderr, "\\\\");
452 } else if (isprint(ch)) {
453 putc(ch, stderr);
454 } else {
455 fprintf(stderr, "\\%03o", ch);
456 }
457 lastch = ch;
458 }
459 }
460
461 if (traceit)
462 fprintf(stderr, "\n");
463
464 return TRUE;
465}
466
467
468/*
469 * The main program.
470 */
471
472int
473main (int argc, char **argv)
474{
475 struct jpeg_decompress_struct cinfo;
476 struct jpeg_error_mgr jerr;
477#ifdef PROGRESS_REPORT
478 struct cdjpeg_progress_mgr progress;
479#endif
480 int file_index;
481 djpeg_dest_ptr dest_mgr = NULL;
482 FILE * input_file;
483 FILE * output_file;
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000484 unsigned char *inbuffer = NULL;
485 unsigned long insize = 0;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000486 JDIMENSION num_scanlines;
487
488 /* On Mac, fetch a command line. */
489#ifdef USE_CCOMMAND
490 argc = ccommand(&argv);
491#endif
492
493 progname = argv[0];
494 if (progname == NULL || progname[0] == 0)
495 progname = "djpeg"; /* in case C library doesn't provide it */
496
497 /* Initialize the JPEG decompression object with default error handling. */
498 cinfo.err = jpeg_std_error(&jerr);
499 jpeg_create_decompress(&cinfo);
500 /* Add some application-specific error messages (from cderror.h) */
501 jerr.addon_message_table = cdjpeg_message_table;
502 jerr.first_addon_message = JMSG_FIRSTADDONCODE;
503 jerr.last_addon_message = JMSG_LASTADDONCODE;
504
505 /* Insert custom marker processor for COM and APP12.
506 * APP12 is used by some digital camera makers for textual info,
507 * so we provide the ability to display it as text.
508 * If you like, additional APPn marker types can be selected for display,
hbono@chromium.org98626972011-08-03 03:13:08 +0000509 * but don't try to override APP0 or APP14 this way (see libjpeg.txt).
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000510 */
511 jpeg_set_marker_processor(&cinfo, JPEG_COM, print_text_marker);
512 jpeg_set_marker_processor(&cinfo, JPEG_APP0+12, print_text_marker);
513
514 /* Now safe to enable signal catcher. */
515#ifdef NEED_SIGNAL_CATCHER
516 enable_signal_catcher((j_common_ptr) &cinfo);
517#endif
518
519 /* Scan command line to find file names. */
520 /* It is convenient to use just one switch-parsing routine, but the switch
521 * values read here are ignored; we will rescan the switches after opening
522 * the input file.
523 * (Exception: tracing level set here controls verbosity for COM markers
524 * found during jpeg_read_header...)
525 */
526
527 file_index = parse_switches(&cinfo, argc, argv, 0, FALSE);
528
529#ifdef TWO_FILE_COMMANDLINE
530 /* Must have either -outfile switch or explicit output file name */
531 if (outfilename == NULL) {
532 if (file_index != argc-2) {
533 fprintf(stderr, "%s: must name one input and one output file\n",
534 progname);
535 usage();
536 }
537 outfilename = argv[file_index+1];
538 } else {
539 if (file_index != argc-1) {
540 fprintf(stderr, "%s: must name one input and one output file\n",
541 progname);
542 usage();
543 }
544 }
545#else
546 /* Unix style: expect zero or one file name */
547 if (file_index < argc-1) {
548 fprintf(stderr, "%s: only one input file\n", progname);
549 usage();
550 }
551#endif /* TWO_FILE_COMMANDLINE */
552
553 /* Open the input file. */
554 if (file_index < argc) {
555 if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
556 fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
557 exit(EXIT_FAILURE);
558 }
559 } else {
560 /* default input file is stdin */
561 input_file = read_stdin();
562 }
563
564 /* Open the output file. */
565 if (outfilename != NULL) {
566 if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
567 fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
568 exit(EXIT_FAILURE);
569 }
570 } else {
571 /* default output file is stdout */
572 output_file = write_stdout();
573 }
574
575#ifdef PROGRESS_REPORT
576 start_progress_monitor((j_common_ptr) &cinfo, &progress);
577#endif
578
579 /* Specify data source for decompression */
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000580#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
581 if (memsrc) {
582 size_t nbytes;
583 do {
584 inbuffer = (unsigned char *)realloc(inbuffer, insize + INPUT_BUF_SIZE);
585 if (inbuffer == NULL) {
586 fprintf(stderr, "%s: memory allocation failure\n", progname);
587 exit(EXIT_FAILURE);
588 }
589 nbytes = JFREAD(input_file, &inbuffer[insize], INPUT_BUF_SIZE);
590 if (nbytes < INPUT_BUF_SIZE && ferror(input_file)) {
591 if (file_index < argc)
592 fprintf(stderr, "%s: can't read from %s\n", progname,
593 argv[file_index]);
594 else
595 fprintf(stderr, "%s: can't read from stdin\n", progname);
596 }
597 insize += (unsigned long)nbytes;
598 } while (nbytes == INPUT_BUF_SIZE);
599 fprintf(stderr, "Compressed size: %lu bytes\n", insize);
600 jpeg_mem_src(&cinfo, inbuffer, insize);
601 } else
602#endif
603 jpeg_stdio_src(&cinfo, input_file);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000604
605 /* Read file header, set default decompression parameters */
606 (void) jpeg_read_header(&cinfo, TRUE);
607
608 /* Adjust default decompression parameters by re-parsing the options */
609 file_index = parse_switches(&cinfo, argc, argv, 0, TRUE);
610
611 /* Initialize the output module now to let it override any crucial
612 * option settings (for instance, GIF wants to force color quantization).
613 */
614 switch (requested_fmt) {
615#ifdef BMP_SUPPORTED
616 case FMT_BMP:
617 dest_mgr = jinit_write_bmp(&cinfo, FALSE);
618 break;
619 case FMT_OS2:
620 dest_mgr = jinit_write_bmp(&cinfo, TRUE);
621 break;
622#endif
623#ifdef GIF_SUPPORTED
624 case FMT_GIF:
625 dest_mgr = jinit_write_gif(&cinfo);
626 break;
627#endif
628#ifdef PPM_SUPPORTED
629 case FMT_PPM:
630 dest_mgr = jinit_write_ppm(&cinfo);
631 break;
632#endif
633#ifdef RLE_SUPPORTED
634 case FMT_RLE:
635 dest_mgr = jinit_write_rle(&cinfo);
636 break;
637#endif
638#ifdef TARGA_SUPPORTED
639 case FMT_TARGA:
640 dest_mgr = jinit_write_targa(&cinfo);
641 break;
642#endif
643 default:
644 ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT);
645 break;
646 }
647 dest_mgr->output_file = output_file;
648
649 /* Start decompressor */
650 (void) jpeg_start_decompress(&cinfo);
651
Aaron Gablec9c87552015-08-03 09:34:32 -0700652 /* Strip decode */
653 if (strip || skip) {
654 JDIMENSION tmp;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000655
Aaron Gablec9c87552015-08-03 09:34:32 -0700656 /* Check for valid endY. We cannot check this value until after
657 * jpeg_start_decompress() is called. Note that we have already verified
658 * that startY <= endY.
659 */
660 if (endY > cinfo.output_height - 1) {
661 fprintf(stderr, "%s: strip %d-%d exceeds image height %d\n", progname,
662 startY, endY, cinfo.output_height);
663 exit(EXIT_FAILURE);
664 }
665
666 /* Write output file header. This is a hack to ensure that the destination
667 * manager creates an image of the proper size for the partial decode.
668 */
669 tmp = cinfo.output_height;
670 cinfo.output_height = endY - startY + 1;
671 if (skip)
672 cinfo.output_height = tmp - cinfo.output_height;
673 (*dest_mgr->start_output) (&cinfo, dest_mgr);
674 cinfo.output_height = tmp;
675
676 /* Process data */
677 if (skip) {
678 while (cinfo.output_scanline < startY) {
679 num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
680 dest_mgr->buffer_height);
681 (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
682 }
683 jpeg_skip_scanlines(&cinfo, endY - startY + 1);
684 while (cinfo.output_scanline < cinfo.output_height) {
685 num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
686 dest_mgr->buffer_height);
687 (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
688 }
689 } else {
690 jpeg_skip_scanlines(&cinfo, startY);
691 while (cinfo.output_scanline <= endY) {
692 num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
693 dest_mgr->buffer_height);
694 (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
695 }
696 jpeg_skip_scanlines(&cinfo, cinfo.output_height - endY + 1);
697 }
698
699 /* Normal full image decode */
700 } else {
701 /* Write output file header */
702 (*dest_mgr->start_output) (&cinfo, dest_mgr);
703
704 /* Process data */
705 while (cinfo.output_scanline < cinfo.output_height) {
706 num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
707 dest_mgr->buffer_height);
708 (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
709 }
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000710 }
711
712#ifdef PROGRESS_REPORT
713 /* Hack: count final pass as done in case finish_output does an extra pass.
714 * The library won't have updated completed_passes.
715 */
716 progress.pub.completed_passes = progress.pub.total_passes;
717#endif
718
719 /* Finish decompression and release memory.
720 * I must do it in this order because output module has allocated memory
721 * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory.
722 */
723 (*dest_mgr->finish_output) (&cinfo, dest_mgr);
724 (void) jpeg_finish_decompress(&cinfo);
725 jpeg_destroy_decompress(&cinfo);
726
727 /* Close files, if we opened them */
728 if (input_file != stdin)
729 fclose(input_file);
730 if (output_file != stdout)
731 fclose(output_file);
732
733#ifdef PROGRESS_REPORT
734 end_progress_monitor((j_common_ptr) &cinfo);
735#endif
736
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000737 if (memsrc && inbuffer != NULL)
738 free(inbuffer);
739
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000740 /* All done. */
741 exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);
742 return 0; /* suppress no-return-value warnings */
743}