home *** CD-ROM | disk | FTP | other *** search
- /*
- * jdmain.c
- *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains an MS-DOS user interface for the JPEG decompressor.
- * It follows DOS practice more closely than does the standard jdmain.c.
- * This compiles under Borland C or Microsoft C; don't know about others.
- * If you are using jmemnobs.c, #define FREE_MEM_ESTIMATE=0.
- */
-
- #include "jinclude.h"
- #include <stdlib.h> /* to declare exit() */
- #include <string.h> /* string functions */
- #include <signal.h> /* to declare signal() */
-
- #ifdef __TURBOC__
- /* Borland C declarations */
- #include <dir.h> /* for findfirst/findnext */
- typedef struct ffblk FF_DATA;
- #define FF_NAME ff_name
- #define FINDFIRST(path,blk) findfirst(path, blk, 0)
- #define FINDNEXT(blk) findnext(blk)
-
- #include <alloc.h> /* for farcoreleft() */
- /* In Borland C, force -m equal to 95% of farcoreleft figure */
- #define FREE_MEM_ESTIMATE ((farcoreleft() * 95L) / 100L)
-
- #else /* !__TURBOC__ */
- /* Microsoft C declarations */
- #include <dos.h> /* for findfirst/findnext */
- typedef struct find_t FF_DATA;
- #define FF_NAME name
- #define FINDFIRST(path,blk) _dos_findfirst(path, _A_NORMAL, blk)
- #define FINDNEXT(blk) _dos_findnext(blk)
-
- #endif /* __TURBOC__ */
-
- #define READ_BINARY "rb"
- #define WRITE_BINARY "wb"
-
- #ifndef EXIT_FAILURE /* define exit() codes if not provided */
- #define EXIT_FAILURE 1
- #endif
- #ifndef EXIT_SUCCESS
- #define EXIT_SUCCESS 0
- #endif
-
-
- #include "jversion.h" /* for version message */
-
-
- /*
- * PD version of getopt(3).
- */
-
- #include "egetopt.c"
-
-
- /*
- * This list defines the known output image formats
- * (not all of which need be supported by a given version).
- * You can change the default output format by defining DEFAULT_FMT;
- * indeed, you had better do so if you undefine GIF_SUPPORTED.
- */
-
- typedef enum {
- FMT_GIF, /* GIF format */
- FMT_PPM, /* PPM/PGM (PBMPLUS formats) */
- FMT_RLE, /* RLE format */
- FMT_TARGA, /* Targa format */
- FMT_TIFF /* TIFF format */
- } IMAGE_FORMATS;
-
- #ifndef DEFAULT_FMT /* so can override from CFLAGS in Makefile */
- #define DEFAULT_FMT FMT_GIF
- #endif
-
- static IMAGE_FORMATS requested_fmt;
-
-
- /*
- * This routine gets control after the input file header has been read.
- * It must determine what output file format is to be written,
- * and make any other decompression parameter changes that are desirable.
- */
-
- METHODDEF void
- d_ui_method_selection (decompress_info_ptr cinfo)
- {
- /* if grayscale or CMYK input, force similar output; */
- /* else leave the output colorspace as set by options. */
- if (cinfo->jpeg_color_space == CS_GRAYSCALE)
- cinfo->out_color_space = CS_GRAYSCALE;
- else if (cinfo->jpeg_color_space == CS_CMYK)
- cinfo->out_color_space = CS_CMYK;
-
- /* select output file format */
- /* Note: jselwxxx routine may make additional parameter changes,
- * such as forcing color quantization if it's a colormapped format.
- */
- switch (requested_fmt) {
- #ifdef GIF_SUPPORTED
- case FMT_GIF:
- jselwgif(cinfo);
- break;
- #endif
- #ifdef PPM_SUPPORTED
- case FMT_PPM:
- jselwppm(cinfo);
- break;
- #endif
- #ifdef RLE_SUPPORTED
- case FMT_RLE:
- jselwrle(cinfo);
- break;
- #endif
- #ifdef TARGA_SUPPORTED
- case FMT_TARGA:
- jselwtarga(cinfo);
- break;
- #endif
- default:
- ERREXIT(cinfo->emethods, "Unsupported output file format");
- break;
- }
- }
-
-
- /*
- * Signal catcher to ensure that temporary files are removed before aborting.
- * Doesn't do anything during intervals where emethods is NULL.
- */
-
- static external_methods_ptr emethods; /* for access to free_all */
-
- LOCAL void
- signal_catcher (int signum)
- {
- if (emethods != NULL) {
- emethods->trace_level = 0; /* turn off trace output */
- (*emethods->free_all) (); /* clean up memory allocation & temp files */
- }
- exit(EXIT_FAILURE);
- }
-
-
- LOCAL void
- usage (void)
- /* complain about bad command line */
- {
- fprintf(stderr, "Usage: djpeg [switches] inputfile(s)\n");
- fprintf(stderr, "List of input files may use wildcards (* and ?)\n");
- fprintf(stderr, "If input file name has no extension, .JPG is assumed\n");
- fprintf(stderr, "Output filename is same as input filename, except for extension\n");
- fprintf(stderr, "Optional switches:\n");
- #ifdef GIF_SUPPORTED
- fprintf(stderr, " -G Select GIF output, extension .GIF (default)\n");
- #endif
- #ifdef PPM_SUPPORTED
- fprintf(stderr, " -P Select PPM/PGM output, extension .PPM\n");
- #endif
- #ifdef RLE_SUPPORTED
- fprintf(stderr, " -R Select Utah RLE output, extension .RLE\n");
- #endif
- #ifdef TARGA_SUPPORTED
- fprintf(stderr, " -T Select Targa output, extension .TGA\n");
- #endif
- fprintf(stderr, " -g Force grayscale output\n");
- fprintf(stderr, " -q colors Quantize to no more than N colors\n");
- fprintf(stderr, " -1 Use 1-pass quantization (fast, low quality)\n");
- fprintf(stderr, " -D Don't use dithering in quantization\n");
- fprintf(stderr, " -b Apply cross-block smoothing\n");
- #ifndef FREE_MEM_ESTIMATE
- fprintf(stderr, " -m memory Maximum memory to use (default 300K); see USAGE\n");
- #endif
- fprintf(stderr, " -d Generate debug output\n");
- exit(EXIT_FAILURE);
- }
-
-
- /* Display progress report */
-
- METHODDEF void
- progress_monitor (decompress_info_ptr cinfo, long loopcounter, long looplimit)
- {
- if (cinfo->total_passes > 1) {
- fprintf(stderr, "\rPass %d/%d: %3d%% ",
- cinfo->completed_passes+1, cinfo->total_passes,
- (int) (loopcounter*100L/looplimit));
- } else {
- fprintf(stderr, "\r %3d%% ",
- (int) (loopcounter*100L/looplimit));
- }
- fflush(stderr);
- }
-
-
- /*
- * Check for overwrite of an existing file; clear it with user
- */
-
- LOCAL boolean
- is_write_ok (char * outfilename)
- {
- FILE * ofile;
- int ch;
-
- ofile = fopen(outfilename, READ_BINARY);
- if (ofile == NULL)
- return TRUE; /* not present */
- fclose(ofile); /* oops, it is present */
-
- for (;;) {
- fprintf(stderr, "%s already exists, overwrite it? [y/n] ",
- outfilename);
- fflush(stderr);
- ch = getc(stdin);
- fflush(stdin); /* flush rest of line */
- switch (ch) {
- case 'Y':
- case 'y':
- return TRUE;
- case 'N':
- case 'n':
- return FALSE;
- /* otherwise, ask again */
- }
- }
- }
-
-
- /*
- * Save current switch values here --- necessary for multiple input files!
- */
-
- static boolean b_smooth; /* -b */
- static boolean gray_scale; /* -g */
- static int num_colors; /* -q, or 0 if not seen */
- static boolean two_pass_q; /* not -1 */
- static boolean do_dither; /* not -D */
- static long cur_mem; /* -m, or value of FREE_MEM_ESTIMATE */
- static int cur_trace; /* -d */
-
- #define MAX_FNAME_LEN 150
-
-
- /*
- * Process a single input file
- */
-
- LOCAL void
- process_one_file (char * infilename)
- {
- struct decompress_info_struct cinfo;
- struct decompress_methods_struct dc_methods;
- struct external_methods_struct e_methods;
- char outfilename[MAX_FNAME_LEN];
- int i;
-
- /* Select the input and output files */
-
- if ((cinfo.input_file = fopen(infilename, READ_BINARY)) == NULL) {
- fprintf(stderr, "djpeg: can't open %s\n", infilename);
- return;
- }
- /* Make outfilename be infilename with appropriate extension */
- strcpy(outfilename, infilename);
- for (i = strlen(outfilename)-1; i >= 0; i--) {
- switch (outfilename[i]) {
- case ':':
- case '/':
- case '\\':
- i = 0; /* stop scanning */
- break;
- case '.':
- outfilename[i] = '\0'; /* lop off existing extension */
- i = 0; /* stop scanning */
- break;
- default:
- break; /* keep scanning */
- }
- }
- switch (requested_fmt) {
- case FMT_GIF:
- strcat(outfilename, ".GIF");
- break;
- case FMT_PPM:
- strcat(outfilename, ".PPM");
- break;
- case FMT_RLE:
- strcat(outfilename, ".RLE");
- break;
- case FMT_TARGA:
- strcat(outfilename, ".TGA");
- break;
- }
-
- if (! is_write_ok(outfilename)) {
- fclose(cinfo.input_file);
- return;
- }
- if ((cinfo.output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
- fprintf(stderr, "djpeg: can't create %s\n", outfilename);
- fclose(cinfo.input_file);
- return;
- }
-
- /* Initialize the system-dependent method pointers. */
- cinfo.methods = &dc_methods;
- cinfo.emethods = &e_methods;
- jselerror(&e_methods); /* error/trace message routines */
- jselmemmgr(&e_methods); /* memory allocation routines */
- dc_methods.d_ui_method_selection = d_ui_method_selection;
-
- /* Now OK to enable signal catcher. */
- emethods = &e_methods;
-
- /* Set up JPEG parameters. */
- j_d_defaults(&cinfo, TRUE);
- cinfo.do_block_smoothing = b_smooth;
- if (gray_scale)
- cinfo.out_color_space = CS_GRAYSCALE;
- if (num_colors > 0) {
- cinfo.desired_number_of_colors = num_colors;
- cinfo.quantize_colors = TRUE;
- }
- cinfo.two_pass_quantize = two_pass_q;
- cinfo.use_dithering = do_dither;
- e_methods.max_memory_to_use = cur_mem;
- e_methods.trace_level = cur_trace;
-
- /* Start up progress display, unless trace output is on */
- fprintf(stderr, "Decompressing %s => %s\n", infilename, outfilename);
- if (cur_trace == 0)
- dc_methods.progress_monitor = progress_monitor;
-
- /* Set up to read a JFIF or baseline-JPEG file. */
- /* A smarter UI would inspect the first few bytes of the input file */
- /* to determine its type. */
- #ifdef JFIF_SUPPORTED
- jselrjfif(&cinfo);
- #else
- You shoulda defined JFIF_SUPPORTED. /* deliberate syntax error */
- #endif
-
- /* Do it to it! */
- jpeg_decompress(&cinfo);
-
- /* Clear away progress display */
- if (cur_trace == 0)
- fprintf(stderr, "\r \r");
- fflush(stderr);
-
- /* All done. Close files, disable signal catcher */
- fclose(cinfo.input_file);
- fclose(cinfo.output_file);
- emethods = NULL;
- }
-
-
- /*
- * Process one filespec; expand wildcards
- */
-
- LOCAL void
- process_filespec (char * filespec)
- {
- FF_DATA ffblock;
- char infilename[MAX_FNAME_LEN];
- int pathlen, i;
- boolean hasext;
-
- /* Determine whether there is a path and an extension */
- pathlen = 0;
- hasext = FALSE;
- for (i = strlen(filespec)-1; i >= 0; i--) {
- switch (filespec[i]) {
- case ':':
- case '/':
- case '\\':
- pathlen = i+1; /* path part ends here */
- i = 0; /* stop scanning */
- break;
- case '.':
- hasext = TRUE; /* there is an extension */
- break;
- default:
- break; /* keep scanning */
- }
- }
-
- /* Make infilename be filespec; if no explicit extension, attach .JPG */
- strcpy(infilename, filespec);
- if (! hasext)
- strcat(infilename, ".JPG");
-
- /* Scan over matching files */
- if (FINDFIRST(infilename, &ffblock) != 0) {
- fprintf(stderr, "No files matching %s\n", infilename);
- } else {
- do {
- strcpy(infilename, filespec);
- strcpy(infilename + pathlen, ffblock.FF_NAME);
- process_one_file(infilename);
- } while (FINDNEXT(&ffblock) == 0);
- }
- }
-
-
- /*
- * The main program.
- */
-
- GLOBAL int
- main (int argc, char **argv)
- {
- int c;
-
- /* Set up signal catcher. */
- emethods = NULL;
- signal(SIGINT, signal_catcher);
- #ifdef SIGTERM /* not all systems have SIGTERM */
- signal(SIGTERM, signal_catcher);
- #endif
-
- /* Scan command line, process switches */
-
- requested_fmt = DEFAULT_FMT; /* initialize default switch values */
- b_smooth = FALSE;
- gray_scale = FALSE;
- num_colors = 0;
- two_pass_q = TRUE;
- do_dither = TRUE;
- #ifdef FREE_MEM_ESTIMATE
- cur_mem = FREE_MEM_ESTIMATE;
- #else
- cur_mem = 300000L; /* reasonable default for DOS */
- #endif
- cur_trace = 0;
-
- while ((c = egetopt(argc, argv, "GPRTbgq:1Dm:d")) != EOF)
- switch (c) {
- case 'G': /* GIF output format. */
- requested_fmt = FMT_GIF;
- break;
- case 'P': /* PPM output format. */
- requested_fmt = FMT_PPM;
- break;
- case 'R': /* RLE output format. */
- requested_fmt = FMT_RLE;
- break;
- case 'T': /* Targa output format. */
- requested_fmt = FMT_TARGA;
- break;
- case 'b': /* Enable cross-block smoothing. */
- b_smooth = TRUE;
- break;
- case 'g': /* Force grayscale output. */
- gray_scale = TRUE;
- break;
- case 'q': /* Do color quantization. */
- if (optarg == NULL)
- usage();
- if (sscanf(optarg, "%d", &num_colors) != 1)
- usage();
- break;
- case '1': /* Use fast one-pass quantization. */
- two_pass_q = FALSE;
- break;
- case 'D': /* Suppress dithering in color quantization. */
- do_dither = FALSE;
- break;
- case 'm': /* Maximum memory in Kb (or Mb with 'm'). */
- { long lval;
- char ch = 'x';
-
- if (optarg == NULL)
- usage();
- if (sscanf(optarg, "%ld%c", &lval, &ch) < 1)
- usage();
- if (ch == 'm' || ch == 'M')
- lval *= 1000L;
- cur_mem = lval * 1000L;
- }
- break;
- case 'd': /* Debugging. */
- /* On first -d, print version identification */
- if (cur_trace == 0)
- fprintf(stderr, "Independent JPEG Group's DJPEG, version %s\n%s\n",
- JVERSION, JCOPYRIGHT);
- cur_trace++;
- break;
- case '?':
- default:
- usage();
- break;
- }
-
- /* Process file specifications */
- if (optind >= argc)
- usage(); /* no filespecs?? */
-
- while (optind < argc)
- process_filespec(argv[optind++]);
-
- /* All done. */
- exit(EXIT_SUCCESS);
- return 0; /* suppress no-return-value warnings */
- }