1*7dd7cddfSDavid du Colombier /* 2*7dd7cddfSDavid du Colombier * djpeg.c 3*7dd7cddfSDavid du Colombier * 4*7dd7cddfSDavid du Colombier * Copyright (C) 1991-1996, Thomas G. Lane. 5*7dd7cddfSDavid du Colombier * This file is part of the Independent JPEG Group's software. 6*7dd7cddfSDavid du Colombier * For conditions of distribution and use, see the accompanying README file. 7*7dd7cddfSDavid du Colombier * 8*7dd7cddfSDavid du Colombier * This file contains a command-line user interface for the JPEG decompressor. 9*7dd7cddfSDavid du Colombier * It should work on any system with Unix- or MS-DOS-style command lines. 10*7dd7cddfSDavid du Colombier * 11*7dd7cddfSDavid du Colombier * Two different command line styles are permitted, depending on the 12*7dd7cddfSDavid du Colombier * compile-time switch TWO_FILE_COMMANDLINE: 13*7dd7cddfSDavid du Colombier * djpeg [options] inputfile outputfile 14*7dd7cddfSDavid du Colombier * djpeg [options] [inputfile] 15*7dd7cddfSDavid du Colombier * In the second style, output is always to standard output, which you'd 16*7dd7cddfSDavid du Colombier * normally redirect to a file or pipe to some other program. Input is 17*7dd7cddfSDavid du Colombier * either from a named file or from standard input (typically redirected). 18*7dd7cddfSDavid du Colombier * The second style is convenient on Unix but is unhelpful on systems that 19*7dd7cddfSDavid du Colombier * don't support pipes. Also, you MUST use the first style if your system 20*7dd7cddfSDavid du Colombier * doesn't do binary I/O to stdin/stdout. 21*7dd7cddfSDavid du Colombier * To simplify script writing, the "-outfile" switch is provided. The syntax 22*7dd7cddfSDavid du Colombier * djpeg [options] -outfile outputfile inputfile 23*7dd7cddfSDavid du Colombier * works regardless of which command line style is used. 24*7dd7cddfSDavid du Colombier */ 25*7dd7cddfSDavid du Colombier 26*7dd7cddfSDavid du Colombier #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ 27*7dd7cddfSDavid du Colombier #include "jversion.h" /* for version message */ 28*7dd7cddfSDavid du Colombier 29*7dd7cddfSDavid du Colombier #include <ctype.h> /* to declare isprint() */ 30*7dd7cddfSDavid du Colombier 31*7dd7cddfSDavid du Colombier #ifdef USE_CCOMMAND /* command-line reader for Macintosh */ 32*7dd7cddfSDavid du Colombier #ifdef __MWERKS__ 33*7dd7cddfSDavid du Colombier #include <SIOUX.h> /* Metrowerks needs this */ 34*7dd7cddfSDavid du Colombier #include <console.h> /* ... and this */ 35*7dd7cddfSDavid du Colombier #endif 36*7dd7cddfSDavid du Colombier #ifdef THINK_C 37*7dd7cddfSDavid du Colombier #include <console.h> /* Think declares it here */ 38*7dd7cddfSDavid du Colombier #endif 39*7dd7cddfSDavid du Colombier #endif 40*7dd7cddfSDavid du Colombier 41*7dd7cddfSDavid du Colombier 42*7dd7cddfSDavid du Colombier /* Create the add-on message string table. */ 43*7dd7cddfSDavid du Colombier 44*7dd7cddfSDavid du Colombier #define JMESSAGE(code,string) string , 45*7dd7cddfSDavid du Colombier 46*7dd7cddfSDavid du Colombier static const char * const cdjpeg_message_table[] = { 47*7dd7cddfSDavid du Colombier #include "cderror.h" 48*7dd7cddfSDavid du Colombier NULL 49*7dd7cddfSDavid du Colombier }; 50*7dd7cddfSDavid du Colombier 51*7dd7cddfSDavid du Colombier 52*7dd7cddfSDavid du Colombier /* 53*7dd7cddfSDavid du Colombier * This list defines the known output image formats 54*7dd7cddfSDavid du Colombier * (not all of which need be supported by a given version). 55*7dd7cddfSDavid du Colombier * You can change the default output format by defining DEFAULT_FMT; 56*7dd7cddfSDavid du Colombier * indeed, you had better do so if you undefine PPM_SUPPORTED. 57*7dd7cddfSDavid du Colombier */ 58*7dd7cddfSDavid du Colombier 59*7dd7cddfSDavid du Colombier typedef enum { 60*7dd7cddfSDavid du Colombier FMT_BMP, /* BMP format (Windows flavor) */ 61*7dd7cddfSDavid du Colombier FMT_GIF, /* GIF format */ 62*7dd7cddfSDavid du Colombier FMT_OS2, /* BMP format (OS/2 flavor) */ 63*7dd7cddfSDavid du Colombier FMT_PPM, /* PPM/PGM (PBMPLUS formats) */ 64*7dd7cddfSDavid du Colombier FMT_RLE, /* RLE format */ 65*7dd7cddfSDavid du Colombier FMT_TARGA, /* Targa format */ 66*7dd7cddfSDavid du Colombier FMT_TIFF /* TIFF format */ 67*7dd7cddfSDavid du Colombier } IMAGE_FORMATS; 68*7dd7cddfSDavid du Colombier 69*7dd7cddfSDavid du Colombier #ifndef DEFAULT_FMT /* so can override from CFLAGS in Makefile */ 70*7dd7cddfSDavid du Colombier #define DEFAULT_FMT FMT_PPM 71*7dd7cddfSDavid du Colombier #endif 72*7dd7cddfSDavid du Colombier 73*7dd7cddfSDavid du Colombier static IMAGE_FORMATS requested_fmt; 74*7dd7cddfSDavid du Colombier 75*7dd7cddfSDavid du Colombier 76*7dd7cddfSDavid du Colombier /* 77*7dd7cddfSDavid du Colombier * Argument-parsing code. 78*7dd7cddfSDavid du Colombier * The switch parser is designed to be useful with DOS-style command line 79*7dd7cddfSDavid du Colombier * syntax, ie, intermixed switches and file names, where only the switches 80*7dd7cddfSDavid du Colombier * to the left of a given file name affect processing of that file. 81*7dd7cddfSDavid du Colombier * The main program in this file doesn't actually use this capability... 82*7dd7cddfSDavid du Colombier */ 83*7dd7cddfSDavid du Colombier 84*7dd7cddfSDavid du Colombier 85*7dd7cddfSDavid du Colombier static const char * progname; /* program name for error messages */ 86*7dd7cddfSDavid du Colombier static char * outfilename; /* for -outfile switch */ 87*7dd7cddfSDavid du Colombier 88*7dd7cddfSDavid du Colombier 89*7dd7cddfSDavid du Colombier LOCAL(void) 90*7dd7cddfSDavid du Colombier usage (void) 91*7dd7cddfSDavid du Colombier /* complain about bad command line */ 92*7dd7cddfSDavid du Colombier { 93*7dd7cddfSDavid du Colombier fprintf(stderr, "usage: %s [switches] ", progname); 94*7dd7cddfSDavid du Colombier #ifdef TWO_FILE_COMMANDLINE 95*7dd7cddfSDavid du Colombier fprintf(stderr, "inputfile outputfile\n"); 96*7dd7cddfSDavid du Colombier #else 97*7dd7cddfSDavid du Colombier fprintf(stderr, "[inputfile]\n"); 98*7dd7cddfSDavid du Colombier #endif 99*7dd7cddfSDavid du Colombier 100*7dd7cddfSDavid du Colombier fprintf(stderr, "Switches (names may be abbreviated):\n"); 101*7dd7cddfSDavid du Colombier fprintf(stderr, " -colors N Reduce image to no more than N colors\n"); 102*7dd7cddfSDavid du Colombier fprintf(stderr, " -fast Fast, low-quality processing\n"); 103*7dd7cddfSDavid du Colombier fprintf(stderr, " -grayscale Force grayscale output\n"); 104*7dd7cddfSDavid du Colombier #ifdef IDCT_SCALING_SUPPORTED 105*7dd7cddfSDavid du Colombier fprintf(stderr, " -scale M/N Scale output image by fraction M/N, eg, 1/8\n"); 106*7dd7cddfSDavid du Colombier #endif 107*7dd7cddfSDavid du Colombier #ifdef BMP_SUPPORTED 108*7dd7cddfSDavid du Colombier fprintf(stderr, " -bmp Select BMP output format (Windows style)%s\n", 109*7dd7cddfSDavid du Colombier (DEFAULT_FMT == FMT_BMP ? " (default)" : "")); 110*7dd7cddfSDavid du Colombier #endif 111*7dd7cddfSDavid du Colombier #ifdef GIF_SUPPORTED 112*7dd7cddfSDavid du Colombier fprintf(stderr, " -gif Select GIF output format%s\n", 113*7dd7cddfSDavid du Colombier (DEFAULT_FMT == FMT_GIF ? " (default)" : "")); 114*7dd7cddfSDavid du Colombier #endif 115*7dd7cddfSDavid du Colombier #ifdef BMP_SUPPORTED 116*7dd7cddfSDavid du Colombier fprintf(stderr, " -os2 Select BMP output format (OS/2 style)%s\n", 117*7dd7cddfSDavid du Colombier (DEFAULT_FMT == FMT_OS2 ? " (default)" : "")); 118*7dd7cddfSDavid du Colombier #endif 119*7dd7cddfSDavid du Colombier #ifdef PPM_SUPPORTED 120*7dd7cddfSDavid du Colombier fprintf(stderr, " -pnm Select PBMPLUS (PPM/PGM) output format%s\n", 121*7dd7cddfSDavid du Colombier (DEFAULT_FMT == FMT_PPM ? " (default)" : "")); 122*7dd7cddfSDavid du Colombier #endif 123*7dd7cddfSDavid du Colombier #ifdef RLE_SUPPORTED 124*7dd7cddfSDavid du Colombier fprintf(stderr, " -rle Select Utah RLE output format%s\n", 125*7dd7cddfSDavid du Colombier (DEFAULT_FMT == FMT_RLE ? " (default)" : "")); 126*7dd7cddfSDavid du Colombier #endif 127*7dd7cddfSDavid du Colombier #ifdef TARGA_SUPPORTED 128*7dd7cddfSDavid du Colombier fprintf(stderr, " -targa Select Targa output format%s\n", 129*7dd7cddfSDavid du Colombier (DEFAULT_FMT == FMT_TARGA ? " (default)" : "")); 130*7dd7cddfSDavid du Colombier #endif 131*7dd7cddfSDavid du Colombier fprintf(stderr, "Switches for advanced users:\n"); 132*7dd7cddfSDavid du Colombier #ifdef DCT_ISLOW_SUPPORTED 133*7dd7cddfSDavid du Colombier fprintf(stderr, " -dct int Use integer DCT method%s\n", 134*7dd7cddfSDavid du Colombier (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : "")); 135*7dd7cddfSDavid du Colombier #endif 136*7dd7cddfSDavid du Colombier #ifdef DCT_IFAST_SUPPORTED 137*7dd7cddfSDavid du Colombier fprintf(stderr, " -dct fast Use fast integer DCT (less accurate)%s\n", 138*7dd7cddfSDavid du Colombier (JDCT_DEFAULT == JDCT_IFAST ? " (default)" : "")); 139*7dd7cddfSDavid du Colombier #endif 140*7dd7cddfSDavid du Colombier #ifdef DCT_FLOAT_SUPPORTED 141*7dd7cddfSDavid du Colombier fprintf(stderr, " -dct float Use floating-point DCT method%s\n", 142*7dd7cddfSDavid du Colombier (JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : "")); 143*7dd7cddfSDavid du Colombier #endif 144*7dd7cddfSDavid du Colombier fprintf(stderr, " -dither fs Use F-S dithering (default)\n"); 145*7dd7cddfSDavid du Colombier fprintf(stderr, " -dither none Don't use dithering in quantization\n"); 146*7dd7cddfSDavid du Colombier fprintf(stderr, " -dither ordered Use ordered dither (medium speed, quality)\n"); 147*7dd7cddfSDavid du Colombier #ifdef QUANT_2PASS_SUPPORTED 148*7dd7cddfSDavid du Colombier fprintf(stderr, " -map FILE Map to colors used in named image file\n"); 149*7dd7cddfSDavid du Colombier #endif 150*7dd7cddfSDavid du Colombier fprintf(stderr, " -nosmooth Don't use high-quality upsampling\n"); 151*7dd7cddfSDavid du Colombier #ifdef QUANT_1PASS_SUPPORTED 152*7dd7cddfSDavid du Colombier fprintf(stderr, " -onepass Use 1-pass quantization (fast, low quality)\n"); 153*7dd7cddfSDavid du Colombier #endif 154*7dd7cddfSDavid du Colombier fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n"); 155*7dd7cddfSDavid du Colombier fprintf(stderr, " -outfile name Specify name for output file\n"); 156*7dd7cddfSDavid du Colombier fprintf(stderr, " -verbose or -debug Emit debug output\n"); 157*7dd7cddfSDavid du Colombier exit(EXIT_FAILURE); 158*7dd7cddfSDavid du Colombier } 159*7dd7cddfSDavid du Colombier 160*7dd7cddfSDavid du Colombier 161*7dd7cddfSDavid du Colombier LOCAL(int) 162*7dd7cddfSDavid du Colombier parse_switches (j_decompress_ptr cinfo, int argc, char **argv, 163*7dd7cddfSDavid du Colombier int last_file_arg_seen, boolean for_real) 164*7dd7cddfSDavid du Colombier /* Parse optional switches. 165*7dd7cddfSDavid du Colombier * Returns argv[] index of first file-name argument (== argc if none). 166*7dd7cddfSDavid du Colombier * Any file names with indexes <= last_file_arg_seen are ignored; 167*7dd7cddfSDavid du Colombier * they have presumably been processed in a previous iteration. 168*7dd7cddfSDavid du Colombier * (Pass 0 for last_file_arg_seen on the first or only iteration.) 169*7dd7cddfSDavid du Colombier * for_real is FALSE on the first (dummy) pass; we may skip any expensive 170*7dd7cddfSDavid du Colombier * processing. 171*7dd7cddfSDavid du Colombier */ 172*7dd7cddfSDavid du Colombier { 173*7dd7cddfSDavid du Colombier int argn; 174*7dd7cddfSDavid du Colombier char * arg; 175*7dd7cddfSDavid du Colombier 176*7dd7cddfSDavid du Colombier /* Set up default JPEG parameters. */ 177*7dd7cddfSDavid du Colombier requested_fmt = DEFAULT_FMT; /* set default output file format */ 178*7dd7cddfSDavid du Colombier outfilename = NULL; 179*7dd7cddfSDavid du Colombier cinfo->err->trace_level = 0; 180*7dd7cddfSDavid du Colombier 181*7dd7cddfSDavid du Colombier /* Scan command line options, adjust parameters */ 182*7dd7cddfSDavid du Colombier 183*7dd7cddfSDavid du Colombier for (argn = 1; argn < argc; argn++) { 184*7dd7cddfSDavid du Colombier arg = argv[argn]; 185*7dd7cddfSDavid du Colombier if (*arg != '-') { 186*7dd7cddfSDavid du Colombier /* Not a switch, must be a file name argument */ 187*7dd7cddfSDavid du Colombier if (argn <= last_file_arg_seen) { 188*7dd7cddfSDavid du Colombier outfilename = NULL; /* -outfile applies to just one input file */ 189*7dd7cddfSDavid du Colombier continue; /* ignore this name if previously processed */ 190*7dd7cddfSDavid du Colombier } 191*7dd7cddfSDavid du Colombier break; /* else done parsing switches */ 192*7dd7cddfSDavid du Colombier } 193*7dd7cddfSDavid du Colombier arg++; /* advance past switch marker character */ 194*7dd7cddfSDavid du Colombier 195*7dd7cddfSDavid du Colombier if (keymatch(arg, "bmp", 1)) { 196*7dd7cddfSDavid du Colombier /* BMP output format. */ 197*7dd7cddfSDavid du Colombier requested_fmt = FMT_BMP; 198*7dd7cddfSDavid du Colombier 199*7dd7cddfSDavid du Colombier } else if (keymatch(arg, "colors", 1) || keymatch(arg, "colours", 1) || 200*7dd7cddfSDavid du Colombier keymatch(arg, "quantize", 1) || keymatch(arg, "quantise", 1)) { 201*7dd7cddfSDavid du Colombier /* Do color quantization. */ 202*7dd7cddfSDavid du Colombier int val; 203*7dd7cddfSDavid du Colombier 204*7dd7cddfSDavid du Colombier if (++argn >= argc) /* advance to next argument */ 205*7dd7cddfSDavid du Colombier usage(); 206*7dd7cddfSDavid du Colombier if (sscanf(argv[argn], "%d", &val) != 1) 207*7dd7cddfSDavid du Colombier usage(); 208*7dd7cddfSDavid du Colombier cinfo->desired_number_of_colors = val; 209*7dd7cddfSDavid du Colombier cinfo->quantize_colors = TRUE; 210*7dd7cddfSDavid du Colombier 211*7dd7cddfSDavid du Colombier } else if (keymatch(arg, "dct", 2)) { 212*7dd7cddfSDavid du Colombier /* Select IDCT algorithm. */ 213*7dd7cddfSDavid du Colombier if (++argn >= argc) /* advance to next argument */ 214*7dd7cddfSDavid du Colombier usage(); 215*7dd7cddfSDavid du Colombier if (keymatch(argv[argn], "int", 1)) { 216*7dd7cddfSDavid du Colombier cinfo->dct_method = JDCT_ISLOW; 217*7dd7cddfSDavid du Colombier } else if (keymatch(argv[argn], "fast", 2)) { 218*7dd7cddfSDavid du Colombier cinfo->dct_method = JDCT_IFAST; 219*7dd7cddfSDavid du Colombier } else if (keymatch(argv[argn], "float", 2)) { 220*7dd7cddfSDavid du Colombier cinfo->dct_method = JDCT_FLOAT; 221*7dd7cddfSDavid du Colombier } else 222*7dd7cddfSDavid du Colombier usage(); 223*7dd7cddfSDavid du Colombier 224*7dd7cddfSDavid du Colombier } else if (keymatch(arg, "dither", 2)) { 225*7dd7cddfSDavid du Colombier /* Select dithering algorithm. */ 226*7dd7cddfSDavid du Colombier if (++argn >= argc) /* advance to next argument */ 227*7dd7cddfSDavid du Colombier usage(); 228*7dd7cddfSDavid du Colombier if (keymatch(argv[argn], "fs", 2)) { 229*7dd7cddfSDavid du Colombier cinfo->dither_mode = JDITHER_FS; 230*7dd7cddfSDavid du Colombier } else if (keymatch(argv[argn], "none", 2)) { 231*7dd7cddfSDavid du Colombier cinfo->dither_mode = JDITHER_NONE; 232*7dd7cddfSDavid du Colombier } else if (keymatch(argv[argn], "ordered", 2)) { 233*7dd7cddfSDavid du Colombier cinfo->dither_mode = JDITHER_ORDERED; 234*7dd7cddfSDavid du Colombier } else 235*7dd7cddfSDavid du Colombier usage(); 236*7dd7cddfSDavid du Colombier 237*7dd7cddfSDavid du Colombier } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) { 238*7dd7cddfSDavid du Colombier /* Enable debug printouts. */ 239*7dd7cddfSDavid du Colombier /* On first -d, print version identification */ 240*7dd7cddfSDavid du Colombier static boolean printed_version = FALSE; 241*7dd7cddfSDavid du Colombier 242*7dd7cddfSDavid du Colombier if (! printed_version) { 243*7dd7cddfSDavid du Colombier fprintf(stderr, "Independent JPEG Group's DJPEG, version %s\n%s\n", 244*7dd7cddfSDavid du Colombier JVERSION, JCOPYRIGHT); 245*7dd7cddfSDavid du Colombier printed_version = TRUE; 246*7dd7cddfSDavid du Colombier } 247*7dd7cddfSDavid du Colombier cinfo->err->trace_level++; 248*7dd7cddfSDavid du Colombier 249*7dd7cddfSDavid du Colombier } else if (keymatch(arg, "fast", 1)) { 250*7dd7cddfSDavid du Colombier /* Select recommended processing options for quick-and-dirty output. */ 251*7dd7cddfSDavid du Colombier cinfo->two_pass_quantize = FALSE; 252*7dd7cddfSDavid du Colombier cinfo->dither_mode = JDITHER_ORDERED; 253*7dd7cddfSDavid du Colombier if (! cinfo->quantize_colors) /* don't override an earlier -colors */ 254*7dd7cddfSDavid du Colombier cinfo->desired_number_of_colors = 216; 255*7dd7cddfSDavid du Colombier cinfo->dct_method = JDCT_FASTEST; 256*7dd7cddfSDavid du Colombier cinfo->do_fancy_upsampling = FALSE; 257*7dd7cddfSDavid du Colombier 258*7dd7cddfSDavid du Colombier } else if (keymatch(arg, "gif", 1)) { 259*7dd7cddfSDavid du Colombier /* GIF output format. */ 260*7dd7cddfSDavid du Colombier requested_fmt = FMT_GIF; 261*7dd7cddfSDavid du Colombier 262*7dd7cddfSDavid du Colombier } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) { 263*7dd7cddfSDavid du Colombier /* Force monochrome output. */ 264*7dd7cddfSDavid du Colombier cinfo->out_color_space = JCS_GRAYSCALE; 265*7dd7cddfSDavid du Colombier 266*7dd7cddfSDavid du Colombier } else if (keymatch(arg, "map", 3)) { 267*7dd7cddfSDavid du Colombier /* Quantize to a color map taken from an input file. */ 268*7dd7cddfSDavid du Colombier if (++argn >= argc) /* advance to next argument */ 269*7dd7cddfSDavid du Colombier usage(); 270*7dd7cddfSDavid du Colombier if (for_real) { /* too expensive to do twice! */ 271*7dd7cddfSDavid du Colombier #ifdef QUANT_2PASS_SUPPORTED /* otherwise can't quantize to supplied map */ 272*7dd7cddfSDavid du Colombier FILE * mapfile; 273*7dd7cddfSDavid du Colombier 274*7dd7cddfSDavid du Colombier if ((mapfile = fopen(argv[argn], READ_BINARY)) == NULL) { 275*7dd7cddfSDavid du Colombier fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); 276*7dd7cddfSDavid du Colombier exit(EXIT_FAILURE); 277*7dd7cddfSDavid du Colombier } 278*7dd7cddfSDavid du Colombier read_color_map(cinfo, mapfile); 279*7dd7cddfSDavid du Colombier fclose(mapfile); 280*7dd7cddfSDavid du Colombier cinfo->quantize_colors = TRUE; 281*7dd7cddfSDavid du Colombier #else 282*7dd7cddfSDavid du Colombier ERREXIT(cinfo, JERR_NOT_COMPILED); 283*7dd7cddfSDavid du Colombier #endif 284*7dd7cddfSDavid du Colombier } 285*7dd7cddfSDavid du Colombier 286*7dd7cddfSDavid du Colombier } else if (keymatch(arg, "maxmemory", 3)) { 287*7dd7cddfSDavid du Colombier /* Maximum memory in Kb (or Mb with 'm'). */ 288*7dd7cddfSDavid du Colombier long lval; 289*7dd7cddfSDavid du Colombier char ch = 'x'; 290*7dd7cddfSDavid du Colombier 291*7dd7cddfSDavid du Colombier if (++argn >= argc) /* advance to next argument */ 292*7dd7cddfSDavid du Colombier usage(); 293*7dd7cddfSDavid du Colombier if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) 294*7dd7cddfSDavid du Colombier usage(); 295*7dd7cddfSDavid du Colombier if (ch == 'm' || ch == 'M') 296*7dd7cddfSDavid du Colombier lval *= 1000L; 297*7dd7cddfSDavid du Colombier cinfo->mem->max_memory_to_use = lval * 1000L; 298*7dd7cddfSDavid du Colombier 299*7dd7cddfSDavid du Colombier } else if (keymatch(arg, "nosmooth", 3)) { 300*7dd7cddfSDavid du Colombier /* Suppress fancy upsampling */ 301*7dd7cddfSDavid du Colombier cinfo->do_fancy_upsampling = FALSE; 302*7dd7cddfSDavid du Colombier 303*7dd7cddfSDavid du Colombier } else if (keymatch(arg, "onepass", 3)) { 304*7dd7cddfSDavid du Colombier /* Use fast one-pass quantization. */ 305*7dd7cddfSDavid du Colombier cinfo->two_pass_quantize = FALSE; 306*7dd7cddfSDavid du Colombier 307*7dd7cddfSDavid du Colombier } else if (keymatch(arg, "os2", 3)) { 308*7dd7cddfSDavid du Colombier /* BMP output format (OS/2 flavor). */ 309*7dd7cddfSDavid du Colombier requested_fmt = FMT_OS2; 310*7dd7cddfSDavid du Colombier 311*7dd7cddfSDavid du Colombier } else if (keymatch(arg, "outfile", 4)) { 312*7dd7cddfSDavid du Colombier /* Set output file name. */ 313*7dd7cddfSDavid du Colombier if (++argn >= argc) /* advance to next argument */ 314*7dd7cddfSDavid du Colombier usage(); 315*7dd7cddfSDavid du Colombier outfilename = argv[argn]; /* save it away for later use */ 316*7dd7cddfSDavid du Colombier 317*7dd7cddfSDavid du Colombier } else if (keymatch(arg, "pnm", 1) || keymatch(arg, "ppm", 1)) { 318*7dd7cddfSDavid du Colombier /* PPM/PGM output format. */ 319*7dd7cddfSDavid du Colombier requested_fmt = FMT_PPM; 320*7dd7cddfSDavid du Colombier 321*7dd7cddfSDavid du Colombier } else if (keymatch(arg, "rle", 1)) { 322*7dd7cddfSDavid du Colombier /* RLE output format. */ 323*7dd7cddfSDavid du Colombier requested_fmt = FMT_RLE; 324*7dd7cddfSDavid du Colombier 325*7dd7cddfSDavid du Colombier } else if (keymatch(arg, "scale", 1)) { 326*7dd7cddfSDavid du Colombier /* Scale the output image by a fraction M/N. */ 327*7dd7cddfSDavid du Colombier if (++argn >= argc) /* advance to next argument */ 328*7dd7cddfSDavid du Colombier usage(); 329*7dd7cddfSDavid du Colombier if (sscanf(argv[argn], "%d/%d", 330*7dd7cddfSDavid du Colombier &cinfo->scale_num, &cinfo->scale_denom) != 2) 331*7dd7cddfSDavid du Colombier usage(); 332*7dd7cddfSDavid du Colombier 333*7dd7cddfSDavid du Colombier } else if (keymatch(arg, "targa", 1)) { 334*7dd7cddfSDavid du Colombier /* Targa output format. */ 335*7dd7cddfSDavid du Colombier requested_fmt = FMT_TARGA; 336*7dd7cddfSDavid du Colombier 337*7dd7cddfSDavid du Colombier } else { 338*7dd7cddfSDavid du Colombier usage(); /* bogus switch */ 339*7dd7cddfSDavid du Colombier } 340*7dd7cddfSDavid du Colombier } 341*7dd7cddfSDavid du Colombier 342*7dd7cddfSDavid du Colombier return argn; /* return index of next arg (file name) */ 343*7dd7cddfSDavid du Colombier } 344*7dd7cddfSDavid du Colombier 345*7dd7cddfSDavid du Colombier 346*7dd7cddfSDavid du Colombier /* 347*7dd7cddfSDavid du Colombier * Marker processor for COM markers. 348*7dd7cddfSDavid du Colombier * This replaces the library's built-in processor, which just skips the marker. 349*7dd7cddfSDavid du Colombier * We want to print out the marker as text, if possible. 350*7dd7cddfSDavid du Colombier * Note this code relies on a non-suspending data source. 351*7dd7cddfSDavid du Colombier */ 352*7dd7cddfSDavid du Colombier 353*7dd7cddfSDavid du Colombier LOCAL(unsigned int) 354*7dd7cddfSDavid du Colombier jpeg_getc (j_decompress_ptr cinfo) 355*7dd7cddfSDavid du Colombier /* Read next byte */ 356*7dd7cddfSDavid du Colombier { 357*7dd7cddfSDavid du Colombier struct jpeg_source_mgr * datasrc = cinfo->src; 358*7dd7cddfSDavid du Colombier 359*7dd7cddfSDavid du Colombier if (datasrc->bytes_in_buffer == 0) { 360*7dd7cddfSDavid du Colombier if (! (*datasrc->fill_input_buffer) (cinfo)) 361*7dd7cddfSDavid du Colombier ERREXIT(cinfo, JERR_CANT_SUSPEND); 362*7dd7cddfSDavid du Colombier } 363*7dd7cddfSDavid du Colombier datasrc->bytes_in_buffer--; 364*7dd7cddfSDavid du Colombier return GETJOCTET(*datasrc->next_input_byte++); 365*7dd7cddfSDavid du Colombier } 366*7dd7cddfSDavid du Colombier 367*7dd7cddfSDavid du Colombier 368*7dd7cddfSDavid du Colombier METHODDEF(boolean) 369*7dd7cddfSDavid du Colombier COM_handler (j_decompress_ptr cinfo) 370*7dd7cddfSDavid du Colombier { 371*7dd7cddfSDavid du Colombier boolean traceit = (cinfo->err->trace_level >= 1); 372*7dd7cddfSDavid du Colombier INT32 length; 373*7dd7cddfSDavid du Colombier unsigned int ch; 374*7dd7cddfSDavid du Colombier unsigned int lastch = 0; 375*7dd7cddfSDavid du Colombier 376*7dd7cddfSDavid du Colombier length = jpeg_getc(cinfo) << 8; 377*7dd7cddfSDavid du Colombier length += jpeg_getc(cinfo); 378*7dd7cddfSDavid du Colombier length -= 2; /* discount the length word itself */ 379*7dd7cddfSDavid du Colombier 380*7dd7cddfSDavid du Colombier if (traceit) 381*7dd7cddfSDavid du Colombier fprintf(stderr, "Comment, length %ld:\n", (long) length); 382*7dd7cddfSDavid du Colombier 383*7dd7cddfSDavid du Colombier while (--length >= 0) { 384*7dd7cddfSDavid du Colombier ch = jpeg_getc(cinfo); 385*7dd7cddfSDavid du Colombier if (traceit) { 386*7dd7cddfSDavid du Colombier /* Emit the character in a readable form. 387*7dd7cddfSDavid du Colombier * Nonprintables are converted to \nnn form, 388*7dd7cddfSDavid du Colombier * while \ is converted to \\. 389*7dd7cddfSDavid du Colombier * Newlines in CR, CR/LF, or LF form will be printed as one newline. 390*7dd7cddfSDavid du Colombier */ 391*7dd7cddfSDavid du Colombier if (ch == '\r') { 392*7dd7cddfSDavid du Colombier fprintf(stderr, "\n"); 393*7dd7cddfSDavid du Colombier } else if (ch == '\n') { 394*7dd7cddfSDavid du Colombier if (lastch != '\r') 395*7dd7cddfSDavid du Colombier fprintf(stderr, "\n"); 396*7dd7cddfSDavid du Colombier } else if (ch == '\\') { 397*7dd7cddfSDavid du Colombier fprintf(stderr, "\\\\"); 398*7dd7cddfSDavid du Colombier } else if (isprint(ch)) { 399*7dd7cddfSDavid du Colombier putc(ch, stderr); 400*7dd7cddfSDavid du Colombier } else { 401*7dd7cddfSDavid du Colombier fprintf(stderr, "\\%03o", ch); 402*7dd7cddfSDavid du Colombier } 403*7dd7cddfSDavid du Colombier lastch = ch; 404*7dd7cddfSDavid du Colombier } 405*7dd7cddfSDavid du Colombier } 406*7dd7cddfSDavid du Colombier 407*7dd7cddfSDavid du Colombier if (traceit) 408*7dd7cddfSDavid du Colombier fprintf(stderr, "\n"); 409*7dd7cddfSDavid du Colombier 410*7dd7cddfSDavid du Colombier return TRUE; 411*7dd7cddfSDavid du Colombier } 412*7dd7cddfSDavid du Colombier 413*7dd7cddfSDavid du Colombier 414*7dd7cddfSDavid du Colombier /* 415*7dd7cddfSDavid du Colombier * The main program. 416*7dd7cddfSDavid du Colombier */ 417*7dd7cddfSDavid du Colombier 418*7dd7cddfSDavid du Colombier int 419*7dd7cddfSDavid du Colombier main (int argc, char **argv) 420*7dd7cddfSDavid du Colombier { 421*7dd7cddfSDavid du Colombier struct jpeg_decompress_struct cinfo; 422*7dd7cddfSDavid du Colombier struct jpeg_error_mgr jerr; 423*7dd7cddfSDavid du Colombier #ifdef PROGRESS_REPORT 424*7dd7cddfSDavid du Colombier struct cdjpeg_progress_mgr progress; 425*7dd7cddfSDavid du Colombier #endif 426*7dd7cddfSDavid du Colombier int file_index; 427*7dd7cddfSDavid du Colombier djpeg_dest_ptr dest_mgr = NULL; 428*7dd7cddfSDavid du Colombier FILE * input_file; 429*7dd7cddfSDavid du Colombier FILE * output_file; 430*7dd7cddfSDavid du Colombier JDIMENSION num_scanlines; 431*7dd7cddfSDavid du Colombier 432*7dd7cddfSDavid du Colombier /* On Mac, fetch a command line. */ 433*7dd7cddfSDavid du Colombier #ifdef USE_CCOMMAND 434*7dd7cddfSDavid du Colombier argc = ccommand(&argv); 435*7dd7cddfSDavid du Colombier #endif 436*7dd7cddfSDavid du Colombier 437*7dd7cddfSDavid du Colombier progname = argv[0]; 438*7dd7cddfSDavid du Colombier if (progname == NULL || progname[0] == 0) 439*7dd7cddfSDavid du Colombier progname = "djpeg"; /* in case C library doesn't provide it */ 440*7dd7cddfSDavid du Colombier 441*7dd7cddfSDavid du Colombier /* Initialize the JPEG decompression object with default error handling. */ 442*7dd7cddfSDavid du Colombier cinfo.err = jpeg_std_error(&jerr); 443*7dd7cddfSDavid du Colombier jpeg_create_decompress(&cinfo); 444*7dd7cddfSDavid du Colombier /* Add some application-specific error messages (from cderror.h) */ 445*7dd7cddfSDavid du Colombier jerr.addon_message_table = cdjpeg_message_table; 446*7dd7cddfSDavid du Colombier jerr.first_addon_message = JMSG_FIRSTADDONCODE; 447*7dd7cddfSDavid du Colombier jerr.last_addon_message = JMSG_LASTADDONCODE; 448*7dd7cddfSDavid du Colombier /* Insert custom COM marker processor. */ 449*7dd7cddfSDavid du Colombier jpeg_set_marker_processor(&cinfo, JPEG_COM, COM_handler); 450*7dd7cddfSDavid du Colombier 451*7dd7cddfSDavid du Colombier /* Now safe to enable signal catcher. */ 452*7dd7cddfSDavid du Colombier #ifdef NEED_SIGNAL_CATCHER 453*7dd7cddfSDavid du Colombier enable_signal_catcher((j_common_ptr) &cinfo); 454*7dd7cddfSDavid du Colombier #endif 455*7dd7cddfSDavid du Colombier 456*7dd7cddfSDavid du Colombier /* Scan command line to find file names. */ 457*7dd7cddfSDavid du Colombier /* It is convenient to use just one switch-parsing routine, but the switch 458*7dd7cddfSDavid du Colombier * values read here are ignored; we will rescan the switches after opening 459*7dd7cddfSDavid du Colombier * the input file. 460*7dd7cddfSDavid du Colombier * (Exception: tracing level set here controls verbosity for COM markers 461*7dd7cddfSDavid du Colombier * found during jpeg_read_header...) 462*7dd7cddfSDavid du Colombier */ 463*7dd7cddfSDavid du Colombier 464*7dd7cddfSDavid du Colombier file_index = parse_switches(&cinfo, argc, argv, 0, FALSE); 465*7dd7cddfSDavid du Colombier 466*7dd7cddfSDavid du Colombier #ifdef TWO_FILE_COMMANDLINE 467*7dd7cddfSDavid du Colombier /* Must have either -outfile switch or explicit output file name */ 468*7dd7cddfSDavid du Colombier if (outfilename == NULL) { 469*7dd7cddfSDavid du Colombier if (file_index != argc-2) { 470*7dd7cddfSDavid du Colombier fprintf(stderr, "%s: must name one input and one output file\n", 471*7dd7cddfSDavid du Colombier progname); 472*7dd7cddfSDavid du Colombier usage(); 473*7dd7cddfSDavid du Colombier } 474*7dd7cddfSDavid du Colombier outfilename = argv[file_index+1]; 475*7dd7cddfSDavid du Colombier } else { 476*7dd7cddfSDavid du Colombier if (file_index != argc-1) { 477*7dd7cddfSDavid du Colombier fprintf(stderr, "%s: must name one input and one output file\n", 478*7dd7cddfSDavid du Colombier progname); 479*7dd7cddfSDavid du Colombier usage(); 480*7dd7cddfSDavid du Colombier } 481*7dd7cddfSDavid du Colombier } 482*7dd7cddfSDavid du Colombier #else 483*7dd7cddfSDavid du Colombier /* Unix style: expect zero or one file name */ 484*7dd7cddfSDavid du Colombier if (file_index < argc-1) { 485*7dd7cddfSDavid du Colombier fprintf(stderr, "%s: only one input file\n", progname); 486*7dd7cddfSDavid du Colombier usage(); 487*7dd7cddfSDavid du Colombier } 488*7dd7cddfSDavid du Colombier #endif /* TWO_FILE_COMMANDLINE */ 489*7dd7cddfSDavid du Colombier 490*7dd7cddfSDavid du Colombier /* Open the input file. */ 491*7dd7cddfSDavid du Colombier if (file_index < argc) { 492*7dd7cddfSDavid du Colombier if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { 493*7dd7cddfSDavid du Colombier fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); 494*7dd7cddfSDavid du Colombier exit(EXIT_FAILURE); 495*7dd7cddfSDavid du Colombier } 496*7dd7cddfSDavid du Colombier } else { 497*7dd7cddfSDavid du Colombier /* default input file is stdin */ 498*7dd7cddfSDavid du Colombier input_file = read_stdin(); 499*7dd7cddfSDavid du Colombier } 500*7dd7cddfSDavid du Colombier 501*7dd7cddfSDavid du Colombier /* Open the output file. */ 502*7dd7cddfSDavid du Colombier if (outfilename != NULL) { 503*7dd7cddfSDavid du Colombier if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { 504*7dd7cddfSDavid du Colombier fprintf(stderr, "%s: can't open %s\n", progname, outfilename); 505*7dd7cddfSDavid du Colombier exit(EXIT_FAILURE); 506*7dd7cddfSDavid du Colombier } 507*7dd7cddfSDavid du Colombier } else { 508*7dd7cddfSDavid du Colombier /* default output file is stdout */ 509*7dd7cddfSDavid du Colombier output_file = write_stdout(); 510*7dd7cddfSDavid du Colombier } 511*7dd7cddfSDavid du Colombier 512*7dd7cddfSDavid du Colombier #ifdef PROGRESS_REPORT 513*7dd7cddfSDavid du Colombier start_progress_monitor((j_common_ptr) &cinfo, &progress); 514*7dd7cddfSDavid du Colombier #endif 515*7dd7cddfSDavid du Colombier 516*7dd7cddfSDavid du Colombier /* Specify data source for decompression */ 517*7dd7cddfSDavid du Colombier jpeg_stdio_src(&cinfo, input_file); 518*7dd7cddfSDavid du Colombier 519*7dd7cddfSDavid du Colombier /* Read file header, set default decompression parameters */ 520*7dd7cddfSDavid du Colombier (void) jpeg_read_header(&cinfo, TRUE); 521*7dd7cddfSDavid du Colombier 522*7dd7cddfSDavid du Colombier /* Adjust default decompression parameters by re-parsing the options */ 523*7dd7cddfSDavid du Colombier file_index = parse_switches(&cinfo, argc, argv, 0, TRUE); 524*7dd7cddfSDavid du Colombier 525*7dd7cddfSDavid du Colombier /* Initialize the output module now to let it override any crucial 526*7dd7cddfSDavid du Colombier * option settings (for instance, GIF wants to force color quantization). 527*7dd7cddfSDavid du Colombier */ 528*7dd7cddfSDavid du Colombier switch (requested_fmt) { 529*7dd7cddfSDavid du Colombier #ifdef BMP_SUPPORTED 530*7dd7cddfSDavid du Colombier case FMT_BMP: 531*7dd7cddfSDavid du Colombier dest_mgr = jinit_write_bmp(&cinfo, FALSE); 532*7dd7cddfSDavid du Colombier break; 533*7dd7cddfSDavid du Colombier case FMT_OS2: 534*7dd7cddfSDavid du Colombier dest_mgr = jinit_write_bmp(&cinfo, TRUE); 535*7dd7cddfSDavid du Colombier break; 536*7dd7cddfSDavid du Colombier #endif 537*7dd7cddfSDavid du Colombier #ifdef GIF_SUPPORTED 538*7dd7cddfSDavid du Colombier case FMT_GIF: 539*7dd7cddfSDavid du Colombier dest_mgr = jinit_write_gif(&cinfo); 540*7dd7cddfSDavid du Colombier break; 541*7dd7cddfSDavid du Colombier #endif 542*7dd7cddfSDavid du Colombier #ifdef PPM_SUPPORTED 543*7dd7cddfSDavid du Colombier case FMT_PPM: 544*7dd7cddfSDavid du Colombier dest_mgr = jinit_write_ppm(&cinfo); 545*7dd7cddfSDavid du Colombier break; 546*7dd7cddfSDavid du Colombier #endif 547*7dd7cddfSDavid du Colombier #ifdef RLE_SUPPORTED 548*7dd7cddfSDavid du Colombier case FMT_RLE: 549*7dd7cddfSDavid du Colombier dest_mgr = jinit_write_rle(&cinfo); 550*7dd7cddfSDavid du Colombier break; 551*7dd7cddfSDavid du Colombier #endif 552*7dd7cddfSDavid du Colombier #ifdef TARGA_SUPPORTED 553*7dd7cddfSDavid du Colombier case FMT_TARGA: 554*7dd7cddfSDavid du Colombier dest_mgr = jinit_write_targa(&cinfo); 555*7dd7cddfSDavid du Colombier break; 556*7dd7cddfSDavid du Colombier #endif 557*7dd7cddfSDavid du Colombier default: 558*7dd7cddfSDavid du Colombier ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT); 559*7dd7cddfSDavid du Colombier break; 560*7dd7cddfSDavid du Colombier } 561*7dd7cddfSDavid du Colombier dest_mgr->output_file = output_file; 562*7dd7cddfSDavid du Colombier 563*7dd7cddfSDavid du Colombier /* Start decompressor */ 564*7dd7cddfSDavid du Colombier (void) jpeg_start_decompress(&cinfo); 565*7dd7cddfSDavid du Colombier 566*7dd7cddfSDavid du Colombier /* Write output file header */ 567*7dd7cddfSDavid du Colombier (*dest_mgr->start_output) (&cinfo, dest_mgr); 568*7dd7cddfSDavid du Colombier 569*7dd7cddfSDavid du Colombier /* Process data */ 570*7dd7cddfSDavid du Colombier while (cinfo.output_scanline < cinfo.output_height) { 571*7dd7cddfSDavid du Colombier num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, 572*7dd7cddfSDavid du Colombier dest_mgr->buffer_height); 573*7dd7cddfSDavid du Colombier (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); 574*7dd7cddfSDavid du Colombier } 575*7dd7cddfSDavid du Colombier 576*7dd7cddfSDavid du Colombier #ifdef PROGRESS_REPORT 577*7dd7cddfSDavid du Colombier /* Hack: count final pass as done in case finish_output does an extra pass. 578*7dd7cddfSDavid du Colombier * The library won't have updated completed_passes. 579*7dd7cddfSDavid du Colombier */ 580*7dd7cddfSDavid du Colombier progress.pub.completed_passes = progress.pub.total_passes; 581*7dd7cddfSDavid du Colombier #endif 582*7dd7cddfSDavid du Colombier 583*7dd7cddfSDavid du Colombier /* Finish decompression and release memory. 584*7dd7cddfSDavid du Colombier * I must do it in this order because output module has allocated memory 585*7dd7cddfSDavid du Colombier * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory. 586*7dd7cddfSDavid du Colombier */ 587*7dd7cddfSDavid du Colombier (*dest_mgr->finish_output) (&cinfo, dest_mgr); 588*7dd7cddfSDavid du Colombier (void) jpeg_finish_decompress(&cinfo); 589*7dd7cddfSDavid du Colombier jpeg_destroy_decompress(&cinfo); 590*7dd7cddfSDavid du Colombier 591*7dd7cddfSDavid du Colombier /* Close files, if we opened them */ 592*7dd7cddfSDavid du Colombier if (input_file != stdin) 593*7dd7cddfSDavid du Colombier fclose(input_file); 594*7dd7cddfSDavid du Colombier if (output_file != stdout) 595*7dd7cddfSDavid du Colombier fclose(output_file); 596*7dd7cddfSDavid du Colombier 597*7dd7cddfSDavid du Colombier #ifdef PROGRESS_REPORT 598*7dd7cddfSDavid du Colombier end_progress_monitor((j_common_ptr) &cinfo); 599*7dd7cddfSDavid du Colombier #endif 600*7dd7cddfSDavid du Colombier 601*7dd7cddfSDavid du Colombier /* All done. */ 602*7dd7cddfSDavid du Colombier exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); 603*7dd7cddfSDavid du Colombier return 0; /* suppress no-return-value warnings */ 604*7dd7cddfSDavid du Colombier } 605