Be slightly more targetted in cleaning up jpeg source
This commit is contained in:
parent
c3248e54a4
commit
279f4e5239
|
|
@ -1,181 +0,0 @@
|
|||
/*
|
||||
* cdjpeg.c
|
||||
*
|
||||
* Copyright (C) 1991-1997, 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 common support routines used by the IJG application
|
||||
* programs (cjpeg, djpeg, jpegtran).
|
||||
*/
|
||||
|
||||
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
||||
#include <ctype.h> /* to declare isupper(), tolower() */
|
||||
#ifdef NEED_SIGNAL_CATCHER
|
||||
#include <signal.h> /* to declare signal() */
|
||||
#endif
|
||||
#ifdef USE_SETMODE
|
||||
#include <fcntl.h> /* to declare setmode()'s parameter macros */
|
||||
/* If you have setmode() but not <io.h>, just delete this line: */
|
||||
#include <io.h> /* to declare setmode() */
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Signal catcher to ensure that temporary files are removed before aborting.
|
||||
* NB: for Amiga Manx C this is actually a global routine named _abort();
|
||||
* we put "#define signal_catcher _abort" in jconfig.h. Talk about bogus...
|
||||
*/
|
||||
|
||||
#ifdef NEED_SIGNAL_CATCHER
|
||||
|
||||
static j_common_ptr sig_cinfo;
|
||||
|
||||
void /* must be global for Manx C */
|
||||
signal_catcher (int signum)
|
||||
{
|
||||
if (sig_cinfo != NULL) {
|
||||
if (sig_cinfo->err != NULL) /* turn off trace output */
|
||||
sig_cinfo->err->trace_level = 0;
|
||||
jpeg_destroy(sig_cinfo); /* clean up memory allocation & temp files */
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
GLOBAL(void)
|
||||
enable_signal_catcher (j_common_ptr cinfo)
|
||||
{
|
||||
sig_cinfo = cinfo;
|
||||
#ifdef SIGINT /* not all systems have SIGINT */
|
||||
signal(SIGINT, signal_catcher);
|
||||
#endif
|
||||
#ifdef SIGTERM /* not all systems have SIGTERM */
|
||||
signal(SIGTERM, signal_catcher);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Optional progress monitor: display a percent-done figure on stderr.
|
||||
*/
|
||||
|
||||
#ifdef PROGRESS_REPORT
|
||||
|
||||
METHODDEF(void)
|
||||
progress_monitor (j_common_ptr cinfo)
|
||||
{
|
||||
cd_progress_ptr prog = (cd_progress_ptr) cinfo->progress;
|
||||
int total_passes = prog->pub.total_passes + prog->total_extra_passes;
|
||||
int percent_done = (int) (prog->pub.pass_counter*100L/prog->pub.pass_limit);
|
||||
|
||||
if (percent_done != prog->percent_done) {
|
||||
prog->percent_done = percent_done;
|
||||
if (total_passes > 1) {
|
||||
fprintf(stderr, "\rPass %d/%d: %3d%% ",
|
||||
prog->pub.completed_passes + prog->completed_extra_passes + 1,
|
||||
total_passes, percent_done);
|
||||
} else {
|
||||
fprintf(stderr, "\r %3d%% ", percent_done);
|
||||
}
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GLOBAL(void)
|
||||
start_progress_monitor (j_common_ptr cinfo, cd_progress_ptr progress)
|
||||
{
|
||||
/* Enable progress display, unless trace output is on */
|
||||
if (cinfo->err->trace_level == 0) {
|
||||
progress->pub.progress_monitor = progress_monitor;
|
||||
progress->completed_extra_passes = 0;
|
||||
progress->total_extra_passes = 0;
|
||||
progress->percent_done = -1;
|
||||
cinfo->progress = &progress->pub;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GLOBAL(void)
|
||||
end_progress_monitor (j_common_ptr cinfo)
|
||||
{
|
||||
/* Clear away progress display */
|
||||
if (cinfo->err->trace_level == 0) {
|
||||
fprintf(stderr, "\r \r");
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Case-insensitive matching of possibly-abbreviated keyword switches.
|
||||
* keyword is the constant keyword (must be lower case already),
|
||||
* minchars is length of minimum legal abbreviation.
|
||||
*/
|
||||
|
||||
GLOBAL(boolean)
|
||||
keymatch (char * arg, const char * keyword, int minchars)
|
||||
{
|
||||
register int ca, ck;
|
||||
register int nmatched = 0;
|
||||
|
||||
while ((ca = *arg++) != '\0') {
|
||||
if ((ck = *keyword++) == '\0')
|
||||
return FALSE; /* arg longer than keyword, no good */
|
||||
if (isupper(ca)) /* force arg to lcase (assume ck is already) */
|
||||
ca = tolower(ca);
|
||||
if (ca != ck)
|
||||
return FALSE; /* no good */
|
||||
nmatched++; /* count matched characters */
|
||||
}
|
||||
/* reached end of argument; fail if it's too short for unique abbrev */
|
||||
if (nmatched < minchars)
|
||||
return FALSE;
|
||||
return TRUE; /* A-OK */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Routines to establish binary I/O mode for stdin and stdout.
|
||||
* Non-Unix systems often require some hacking to get out of text mode.
|
||||
*/
|
||||
|
||||
GLOBAL(FILE *)
|
||||
read_stdin (void)
|
||||
{
|
||||
FILE * input_file = stdin;
|
||||
|
||||
#ifdef USE_SETMODE /* need to hack file mode? */
|
||||
setmode(fileno(stdin), O_BINARY);
|
||||
#endif
|
||||
#ifdef USE_FDOPEN /* need to re-open in binary mode? */
|
||||
if ((input_file = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
|
||||
fprintf(stderr, "Cannot reopen stdin\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
return input_file;
|
||||
}
|
||||
|
||||
|
||||
GLOBAL(FILE *)
|
||||
write_stdout (void)
|
||||
{
|
||||
FILE * output_file = stdout;
|
||||
|
||||
#ifdef USE_SETMODE /* need to hack file mode? */
|
||||
setmode(fileno(stdout), O_BINARY);
|
||||
#endif
|
||||
#ifdef USE_FDOPEN /* need to re-open in binary mode? */
|
||||
if ((output_file = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) {
|
||||
fprintf(stderr, "Cannot reopen stdout\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
return output_file;
|
||||
}
|
||||
|
|
@ -1,664 +0,0 @@
|
|||
/*
|
||||
* cjpeg.c
|
||||
*
|
||||
* Copyright (C) 1991-1998, Thomas G. Lane.
|
||||
* Modified 2003-2013 by Guido Vollbeding.
|
||||
* 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 a command-line user interface for the JPEG compressor.
|
||||
* It should work on any system with Unix- or MS-DOS-style command lines.
|
||||
*
|
||||
* Two different command line styles are permitted, depending on the
|
||||
* compile-time switch TWO_FILE_COMMANDLINE:
|
||||
* cjpeg [options] inputfile outputfile
|
||||
* cjpeg [options] [inputfile]
|
||||
* In the second style, output is always to standard output, which you'd
|
||||
* normally redirect to a file or pipe to some other program. Input is
|
||||
* either from a named file or from standard input (typically redirected).
|
||||
* The second style is convenient on Unix but is unhelpful on systems that
|
||||
* don't support pipes. Also, you MUST use the first style if your system
|
||||
* doesn't do binary I/O to stdin/stdout.
|
||||
* To simplify script writing, the "-outfile" switch is provided. The syntax
|
||||
* cjpeg [options] -outfile outputfile inputfile
|
||||
* works regardless of which command line style is used.
|
||||
*/
|
||||
|
||||
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
||||
#include "jversion.h" /* for version message */
|
||||
|
||||
#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
|
||||
#ifdef __MWERKS__
|
||||
#include <SIOUX.h> /* Metrowerks needs this */
|
||||
#include <console.h> /* ... and this */
|
||||
#endif
|
||||
#ifdef THINK_C
|
||||
#include <console.h> /* Think declares it here */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* Create the add-on message string table. */
|
||||
|
||||
#define JMESSAGE(code,string) string ,
|
||||
|
||||
static const char * const cdjpeg_message_table[] = {
|
||||
#include "cderror.h"
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This routine determines what format the input file is,
|
||||
* and selects the appropriate input-reading module.
|
||||
*
|
||||
* To determine which family of input formats the file belongs to,
|
||||
* we may look only at the first byte of the file, since C does not
|
||||
* guarantee that more than one character can be pushed back with ungetc.
|
||||
* Looking at additional bytes would require one of these approaches:
|
||||
* 1) assume we can fseek() the input file (fails for piped input);
|
||||
* 2) assume we can push back more than one character (works in
|
||||
* some C implementations, but unportable);
|
||||
* 3) provide our own buffering (breaks input readers that want to use
|
||||
* stdio directly, such as the RLE library);
|
||||
* or 4) don't put back the data, and modify the input_init methods to assume
|
||||
* they start reading after the start of file (also breaks RLE library).
|
||||
* #1 is attractive for MS-DOS but is untenable on Unix.
|
||||
*
|
||||
* The most portable solution for file types that can't be identified by their
|
||||
* first byte is to make the user tell us what they are. This is also the
|
||||
* only approach for "raw" file types that contain only arbitrary values.
|
||||
* We presently apply this method for Targa files. Most of the time Targa
|
||||
* files start with 0x00, so we recognize that case. Potentially, however,
|
||||
* a Targa file could start with any byte value (byte 0 is the length of the
|
||||
* seldom-used ID field), so we provide a switch to force Targa input mode.
|
||||
*/
|
||||
|
||||
static boolean is_targa; /* records user -targa switch */
|
||||
|
||||
|
||||
LOCAL(cjpeg_source_ptr)
|
||||
select_file_type (j_compress_ptr cinfo, FILE * infile)
|
||||
{
|
||||
int c;
|
||||
|
||||
if (is_targa) {
|
||||
#ifdef TARGA_SUPPORTED
|
||||
return jinit_read_targa(cinfo);
|
||||
#else
|
||||
ERREXIT(cinfo, JERR_TGA_NOTCOMP);
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((c = getc(infile)) == EOF)
|
||||
ERREXIT(cinfo, JERR_INPUT_EMPTY);
|
||||
if (ungetc(c, infile) == EOF)
|
||||
ERREXIT(cinfo, JERR_UNGETC_FAILED);
|
||||
|
||||
switch (c) {
|
||||
#ifdef BMP_SUPPORTED
|
||||
case 'B':
|
||||
return jinit_read_bmp(cinfo);
|
||||
#endif
|
||||
#ifdef GIF_SUPPORTED
|
||||
case 'G':
|
||||
return jinit_read_gif(cinfo);
|
||||
#endif
|
||||
#ifdef PPM_SUPPORTED
|
||||
case 'P':
|
||||
return jinit_read_ppm(cinfo);
|
||||
#endif
|
||||
#ifdef RLE_SUPPORTED
|
||||
case 'R':
|
||||
return jinit_read_rle(cinfo);
|
||||
#endif
|
||||
#ifdef TARGA_SUPPORTED
|
||||
case 0x00:
|
||||
return jinit_read_targa(cinfo);
|
||||
#endif
|
||||
default:
|
||||
ERREXIT(cinfo, JERR_UNKNOWN_FORMAT);
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL; /* suppress compiler warnings */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Argument-parsing code.
|
||||
* The switch parser is designed to be useful with DOS-style command line
|
||||
* syntax, ie, intermixed switches and file names, where only the switches
|
||||
* to the left of a given file name affect processing of that file.
|
||||
* The main program in this file doesn't actually use this capability...
|
||||
*/
|
||||
|
||||
|
||||
static const char * progname; /* program name for error messages */
|
||||
static char * outfilename; /* for -outfile switch */
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
usage (void)
|
||||
/* complain about bad command line */
|
||||
{
|
||||
fprintf(stderr, "usage: %s [switches] ", progname);
|
||||
#ifdef TWO_FILE_COMMANDLINE
|
||||
fprintf(stderr, "inputfile outputfile\n");
|
||||
#else
|
||||
fprintf(stderr, "[inputfile]\n");
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "Switches (names may be abbreviated):\n");
|
||||
fprintf(stderr, " -quality N[,...] Compression quality (0..100; 5-95 is useful range)\n");
|
||||
fprintf(stderr, " -grayscale Create monochrome JPEG file\n");
|
||||
fprintf(stderr, " -rgb Create RGB JPEG file\n");
|
||||
#ifdef ENTROPY_OPT_SUPPORTED
|
||||
fprintf(stderr, " -optimize Optimize Huffman table (smaller file, but slow compression)\n");
|
||||
#endif
|
||||
#ifdef C_PROGRESSIVE_SUPPORTED
|
||||
fprintf(stderr, " -progressive Create progressive JPEG file\n");
|
||||
#endif
|
||||
#ifdef DCT_SCALING_SUPPORTED
|
||||
fprintf(stderr, " -scale M/N Scale image by fraction M/N, eg, 1/2\n");
|
||||
#endif
|
||||
#ifdef TARGA_SUPPORTED
|
||||
fprintf(stderr, " -targa Input file is Targa format (usually not needed)\n");
|
||||
#endif
|
||||
fprintf(stderr, "Switches for advanced users:\n");
|
||||
#ifdef C_ARITH_CODING_SUPPORTED
|
||||
fprintf(stderr, " -arithmetic Use arithmetic coding\n");
|
||||
#endif
|
||||
#ifdef DCT_SCALING_SUPPORTED
|
||||
fprintf(stderr, " -block N DCT block size (1..16; default is 8)\n");
|
||||
#endif
|
||||
#if JPEG_LIB_VERSION_MAJOR >= 9
|
||||
fprintf(stderr, " -rgb1 Create RGB JPEG file with reversible color transform\n");
|
||||
fprintf(stderr, " -bgycc Create big gamut YCC JPEG file\n");
|
||||
#endif
|
||||
#ifdef DCT_ISLOW_SUPPORTED
|
||||
fprintf(stderr, " -dct int Use integer DCT method%s\n",
|
||||
(JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : ""));
|
||||
#endif
|
||||
#ifdef DCT_IFAST_SUPPORTED
|
||||
fprintf(stderr, " -dct fast Use fast integer DCT (less accurate)%s\n",
|
||||
(JDCT_DEFAULT == JDCT_IFAST ? " (default)" : ""));
|
||||
#endif
|
||||
#ifdef DCT_FLOAT_SUPPORTED
|
||||
fprintf(stderr, " -dct float Use floating-point DCT method%s\n",
|
||||
(JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : ""));
|
||||
#endif
|
||||
fprintf(stderr, " -nosmooth Don't use high-quality downsampling\n");
|
||||
fprintf(stderr, " -restart N Set restart interval in rows, or in blocks with B\n");
|
||||
#ifdef INPUT_SMOOTHING_SUPPORTED
|
||||
fprintf(stderr, " -smooth N Smooth dithered input (N=1..100 is strength)\n");
|
||||
#endif
|
||||
fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n");
|
||||
fprintf(stderr, " -outfile name Specify name for output file\n");
|
||||
fprintf(stderr, " -verbose or -debug Emit debug output\n");
|
||||
fprintf(stderr, "Switches for wizards:\n");
|
||||
fprintf(stderr, " -baseline Force baseline quantization tables\n");
|
||||
fprintf(stderr, " -qtables file Use quantization tables given in file\n");
|
||||
fprintf(stderr, " -qslots N[,...] Set component quantization tables\n");
|
||||
fprintf(stderr, " -sample HxV[,...] Set component sampling factors\n");
|
||||
#ifdef C_MULTISCAN_FILES_SUPPORTED
|
||||
fprintf(stderr, " -scans file Create multi-scan JPEG per script file\n");
|
||||
#endif
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
LOCAL(int)
|
||||
parse_switches (j_compress_ptr cinfo, int argc, char **argv,
|
||||
int last_file_arg_seen, boolean for_real)
|
||||
/* Parse optional switches.
|
||||
* Returns argv[] index of first file-name argument (== argc if none).
|
||||
* Any file names with indexes <= last_file_arg_seen are ignored;
|
||||
* they have presumably been processed in a previous iteration.
|
||||
* (Pass 0 for last_file_arg_seen on the first or only iteration.)
|
||||
* for_real is FALSE on the first (dummy) pass; we may skip any expensive
|
||||
* processing.
|
||||
*/
|
||||
{
|
||||
int argn;
|
||||
char * arg;
|
||||
boolean force_baseline;
|
||||
boolean simple_progressive;
|
||||
char * qualityarg = NULL; /* saves -quality parm if any */
|
||||
char * qtablefile = NULL; /* saves -qtables filename if any */
|
||||
char * qslotsarg = NULL; /* saves -qslots parm if any */
|
||||
char * samplearg = NULL; /* saves -sample parm if any */
|
||||
char * scansarg = NULL; /* saves -scans parm if any */
|
||||
|
||||
/* Set up default JPEG parameters. */
|
||||
|
||||
force_baseline = FALSE; /* by default, allow 16-bit quantizers */
|
||||
simple_progressive = FALSE;
|
||||
is_targa = FALSE;
|
||||
outfilename = NULL;
|
||||
cinfo->err->trace_level = 0;
|
||||
|
||||
/* Scan command line options, adjust parameters */
|
||||
|
||||
for (argn = 1; argn < argc; argn++) {
|
||||
arg = argv[argn];
|
||||
if (*arg != '-') {
|
||||
/* Not a switch, must be a file name argument */
|
||||
if (argn <= last_file_arg_seen) {
|
||||
outfilename = NULL; /* -outfile applies to just one input file */
|
||||
continue; /* ignore this name if previously processed */
|
||||
}
|
||||
break; /* else done parsing switches */
|
||||
}
|
||||
arg++; /* advance past switch marker character */
|
||||
|
||||
if (keymatch(arg, "arithmetic", 1)) {
|
||||
/* Use arithmetic coding. */
|
||||
#ifdef C_ARITH_CODING_SUPPORTED
|
||||
cinfo->arith_code = TRUE;
|
||||
#else
|
||||
fprintf(stderr, "%s: sorry, arithmetic coding not supported\n",
|
||||
progname);
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
|
||||
} else if (keymatch(arg, "baseline", 2)) {
|
||||
/* Force baseline-compatible output (8-bit quantizer values). */
|
||||
force_baseline = TRUE;
|
||||
|
||||
} else if (keymatch(arg, "block", 2)) {
|
||||
/* Set DCT block size. */
|
||||
#if defined DCT_SCALING_SUPPORTED && JPEG_LIB_VERSION_MAJOR >= 8 && \
|
||||
(JPEG_LIB_VERSION_MAJOR > 8 || JPEG_LIB_VERSION_MINOR >= 3)
|
||||
int val;
|
||||
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (sscanf(argv[argn], "%d", &val) != 1)
|
||||
usage();
|
||||
if (val < 1 || val > 16)
|
||||
usage();
|
||||
cinfo->block_size = val;
|
||||
#else
|
||||
fprintf(stderr, "%s: sorry, block size setting not supported\n",
|
||||
progname);
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
|
||||
} else if (keymatch(arg, "dct", 2)) {
|
||||
/* Select DCT algorithm. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (keymatch(argv[argn], "int", 1)) {
|
||||
cinfo->dct_method = JDCT_ISLOW;
|
||||
} else if (keymatch(argv[argn], "fast", 2)) {
|
||||
cinfo->dct_method = JDCT_IFAST;
|
||||
} else if (keymatch(argv[argn], "float", 2)) {
|
||||
cinfo->dct_method = JDCT_FLOAT;
|
||||
} else
|
||||
usage();
|
||||
|
||||
} else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
|
||||
/* Enable debug printouts. */
|
||||
/* On first -d, print version identification */
|
||||
static boolean printed_version = FALSE;
|
||||
|
||||
if (! printed_version) {
|
||||
fprintf(stderr, "Independent JPEG Group's CJPEG, version %s\n%s\n",
|
||||
JVERSION, JCOPYRIGHT);
|
||||
printed_version = TRUE;
|
||||
}
|
||||
cinfo->err->trace_level++;
|
||||
|
||||
} else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) {
|
||||
/* Force a monochrome JPEG file to be generated. */
|
||||
jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
|
||||
|
||||
} else if (keymatch(arg, "rgb", 3) || keymatch(arg, "rgb1", 4)) {
|
||||
/* Force an RGB JPEG file to be generated. */
|
||||
#if JPEG_LIB_VERSION_MAJOR >= 9
|
||||
/* Note: Entropy table assignment in jpeg_set_colorspace depends
|
||||
* on color_transform.
|
||||
*/
|
||||
cinfo->color_transform = arg[3] ? JCT_SUBTRACT_GREEN : JCT_NONE;
|
||||
#endif
|
||||
jpeg_set_colorspace(cinfo, JCS_RGB);
|
||||
|
||||
} else if (keymatch(arg, "bgycc", 5)) {
|
||||
/* Force a big gamut YCC JPEG file to be generated. */
|
||||
#if JPEG_LIB_VERSION_MAJOR >= 9 && \
|
||||
(JPEG_LIB_VERSION_MAJOR > 9 || JPEG_LIB_VERSION_MINOR >= 1)
|
||||
jpeg_set_colorspace(cinfo, JCS_BG_YCC);
|
||||
#else
|
||||
fprintf(stderr, "%s: sorry, BG_YCC colorspace not supported\n",
|
||||
progname);
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
|
||||
} else if (keymatch(arg, "maxmemory", 3)) {
|
||||
/* Maximum memory in Kb (or Mb with 'm'). */
|
||||
long lval;
|
||||
char ch = 'x';
|
||||
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
|
||||
usage();
|
||||
if (ch == 'm' || ch == 'M')
|
||||
lval *= 1000L;
|
||||
cinfo->mem->max_memory_to_use = lval * 1000L;
|
||||
|
||||
} else if (keymatch(arg, "nosmooth", 3)) {
|
||||
/* Suppress fancy downsampling. */
|
||||
cinfo->do_fancy_downsampling = FALSE;
|
||||
|
||||
} else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) {
|
||||
/* Enable entropy parm optimization. */
|
||||
#ifdef ENTROPY_OPT_SUPPORTED
|
||||
cinfo->optimize_coding = TRUE;
|
||||
#else
|
||||
fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n",
|
||||
progname);
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
|
||||
} else if (keymatch(arg, "outfile", 4)) {
|
||||
/* Set output file name. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
outfilename = argv[argn]; /* save it away for later use */
|
||||
|
||||
} else if (keymatch(arg, "progressive", 1)) {
|
||||
/* Select simple progressive mode. */
|
||||
#ifdef C_PROGRESSIVE_SUPPORTED
|
||||
simple_progressive = TRUE;
|
||||
/* We must postpone execution until num_components is known. */
|
||||
#else
|
||||
fprintf(stderr, "%s: sorry, progressive output was not compiled\n",
|
||||
progname);
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
|
||||
} else if (keymatch(arg, "quality", 1)) {
|
||||
/* Quality ratings (quantization table scaling factors). */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
qualityarg = argv[argn];
|
||||
|
||||
} else if (keymatch(arg, "qslots", 2)) {
|
||||
/* Quantization table slot numbers. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
qslotsarg = argv[argn];
|
||||
/* Must delay setting qslots until after we have processed any
|
||||
* colorspace-determining switches, since jpeg_set_colorspace sets
|
||||
* default quant table numbers.
|
||||
*/
|
||||
|
||||
} else if (keymatch(arg, "qtables", 2)) {
|
||||
/* Quantization tables fetched from file. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
qtablefile = argv[argn];
|
||||
/* We postpone actually reading the file in case -quality comes later. */
|
||||
|
||||
} else if (keymatch(arg, "restart", 1)) {
|
||||
/* Restart interval in MCU rows (or in MCUs with 'b'). */
|
||||
long lval;
|
||||
char ch = 'x';
|
||||
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
|
||||
usage();
|
||||
if (lval < 0 || lval > 65535L)
|
||||
usage();
|
||||
if (ch == 'b' || ch == 'B') {
|
||||
cinfo->restart_interval = (unsigned int) lval;
|
||||
cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */
|
||||
} else {
|
||||
cinfo->restart_in_rows = (int) lval;
|
||||
/* restart_interval will be computed during startup */
|
||||
}
|
||||
|
||||
} else if (keymatch(arg, "sample", 2)) {
|
||||
/* Set sampling factors. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
samplearg = argv[argn];
|
||||
/* Must delay setting sample factors until after we have processed any
|
||||
* colorspace-determining switches, since jpeg_set_colorspace sets
|
||||
* default sampling factors.
|
||||
*/
|
||||
|
||||
} else if (keymatch(arg, "scale", 4)) {
|
||||
/* Scale the image by a fraction M/N. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (sscanf(argv[argn], "%u/%u",
|
||||
&cinfo->scale_num, &cinfo->scale_denom) != 2)
|
||||
usage();
|
||||
|
||||
} else if (keymatch(arg, "scans", 4)) {
|
||||
/* Set scan script. */
|
||||
#ifdef C_MULTISCAN_FILES_SUPPORTED
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
scansarg = argv[argn];
|
||||
/* We must postpone reading the file in case -progressive appears. */
|
||||
#else
|
||||
fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n",
|
||||
progname);
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
|
||||
} else if (keymatch(arg, "smooth", 2)) {
|
||||
/* Set input smoothing factor. */
|
||||
int val;
|
||||
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (sscanf(argv[argn], "%d", &val) != 1)
|
||||
usage();
|
||||
if (val < 0 || val > 100)
|
||||
usage();
|
||||
cinfo->smoothing_factor = val;
|
||||
|
||||
} else if (keymatch(arg, "targa", 1)) {
|
||||
/* Input file is Targa format. */
|
||||
is_targa = TRUE;
|
||||
|
||||
} else {
|
||||
usage(); /* bogus switch */
|
||||
}
|
||||
}
|
||||
|
||||
/* Post-switch-scanning cleanup */
|
||||
|
||||
if (for_real) {
|
||||
|
||||
/* Set quantization tables for selected quality. */
|
||||
/* Some or all may be overridden if -qtables is present. */
|
||||
if (qualityarg != NULL) /* process -quality if it was present */
|
||||
if (! set_quality_ratings(cinfo, qualityarg, force_baseline))
|
||||
usage();
|
||||
|
||||
if (qtablefile != NULL) /* process -qtables if it was present */
|
||||
if (! read_quant_tables(cinfo, qtablefile, force_baseline))
|
||||
usage();
|
||||
|
||||
if (qslotsarg != NULL) /* process -qslots if it was present */
|
||||
if (! set_quant_slots(cinfo, qslotsarg))
|
||||
usage();
|
||||
|
||||
if (samplearg != NULL) /* process -sample if it was present */
|
||||
if (! set_sample_factors(cinfo, samplearg))
|
||||
usage();
|
||||
|
||||
#ifdef C_PROGRESSIVE_SUPPORTED
|
||||
if (simple_progressive) /* process -progressive; -scans can override */
|
||||
jpeg_simple_progression(cinfo);
|
||||
#endif
|
||||
|
||||
#ifdef C_MULTISCAN_FILES_SUPPORTED
|
||||
if (scansarg != NULL) /* process -scans if it was present */
|
||||
if (! read_scan_script(cinfo, scansarg))
|
||||
usage();
|
||||
#endif
|
||||
}
|
||||
|
||||
return argn; /* return index of next arg (file name) */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The main program.
|
||||
*/
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
struct jpeg_compress_struct cinfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
#ifdef PROGRESS_REPORT
|
||||
struct cdjpeg_progress_mgr progress;
|
||||
#endif
|
||||
int file_index;
|
||||
cjpeg_source_ptr src_mgr;
|
||||
FILE * input_file;
|
||||
FILE * output_file;
|
||||
JDIMENSION num_scanlines;
|
||||
|
||||
/* On Mac, fetch a command line. */
|
||||
#ifdef USE_CCOMMAND
|
||||
argc = ccommand(&argv);
|
||||
#endif
|
||||
|
||||
progname = argv[0];
|
||||
if (progname == NULL || progname[0] == 0)
|
||||
progname = "cjpeg"; /* in case C library doesn't provide it */
|
||||
|
||||
/* Initialize the JPEG compression object with default error handling. */
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
jpeg_create_compress(&cinfo);
|
||||
/* Add some application-specific error messages (from cderror.h) */
|
||||
jerr.addon_message_table = cdjpeg_message_table;
|
||||
jerr.first_addon_message = JMSG_FIRSTADDONCODE;
|
||||
jerr.last_addon_message = JMSG_LASTADDONCODE;
|
||||
|
||||
/* Now safe to enable signal catcher. */
|
||||
#ifdef NEED_SIGNAL_CATCHER
|
||||
enable_signal_catcher((j_common_ptr) &cinfo);
|
||||
#endif
|
||||
|
||||
/* Initialize JPEG parameters.
|
||||
* Much of this may be overridden later.
|
||||
* In particular, we don't yet know the input file's color space,
|
||||
* but we need to provide some value for jpeg_set_defaults() to work.
|
||||
*/
|
||||
|
||||
cinfo.in_color_space = JCS_RGB; /* arbitrary guess */
|
||||
jpeg_set_defaults(&cinfo);
|
||||
|
||||
/* Scan command line to find file names.
|
||||
* It is convenient to use just one switch-parsing routine, but the switch
|
||||
* values read here are ignored; we will rescan the switches after opening
|
||||
* the input file.
|
||||
*/
|
||||
|
||||
file_index = parse_switches(&cinfo, argc, argv, 0, FALSE);
|
||||
|
||||
#ifdef TWO_FILE_COMMANDLINE
|
||||
/* Must have either -outfile switch or explicit output file name */
|
||||
if (outfilename == NULL) {
|
||||
if (file_index != argc-2) {
|
||||
fprintf(stderr, "%s: must name one input and one output file\n",
|
||||
progname);
|
||||
usage();
|
||||
}
|
||||
outfilename = argv[file_index+1];
|
||||
} else {
|
||||
if (file_index != argc-1) {
|
||||
fprintf(stderr, "%s: must name one input and one output file\n",
|
||||
progname);
|
||||
usage();
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* Unix style: expect zero or one file name */
|
||||
if (file_index < argc-1) {
|
||||
fprintf(stderr, "%s: only one input file\n", progname);
|
||||
usage();
|
||||
}
|
||||
#endif /* TWO_FILE_COMMANDLINE */
|
||||
|
||||
/* Open the input file. */
|
||||
if (file_index < argc) {
|
||||
if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
|
||||
fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
/* default input file is stdin */
|
||||
input_file = read_stdin();
|
||||
}
|
||||
|
||||
/* Open the output file. */
|
||||
if (outfilename != NULL) {
|
||||
if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
|
||||
fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
/* default output file is stdout */
|
||||
output_file = write_stdout();
|
||||
}
|
||||
|
||||
#ifdef PROGRESS_REPORT
|
||||
start_progress_monitor((j_common_ptr) &cinfo, &progress);
|
||||
#endif
|
||||
|
||||
/* Figure out the input file format, and set up to read it. */
|
||||
src_mgr = select_file_type(&cinfo, input_file);
|
||||
src_mgr->input_file = input_file;
|
||||
|
||||
/* Read the input file header to obtain file size & colorspace. */
|
||||
(*src_mgr->start_input) (&cinfo, src_mgr);
|
||||
|
||||
/* Now that we know input colorspace, fix colorspace-dependent defaults */
|
||||
jpeg_default_colorspace(&cinfo);
|
||||
|
||||
/* Adjust default compression parameters by re-parsing the options */
|
||||
file_index = parse_switches(&cinfo, argc, argv, 0, TRUE);
|
||||
|
||||
/* Specify data destination for compression */
|
||||
jpeg_stdio_dest(&cinfo, output_file);
|
||||
|
||||
/* Start compressor */
|
||||
jpeg_start_compress(&cinfo, TRUE);
|
||||
|
||||
/* Process data */
|
||||
while (cinfo.next_scanline < cinfo.image_height) {
|
||||
num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr);
|
||||
(void) jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines);
|
||||
}
|
||||
|
||||
/* Finish compression and release memory */
|
||||
(*src_mgr->finish_input) (&cinfo, src_mgr);
|
||||
jpeg_finish_compress(&cinfo);
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
|
||||
/* Close files, if we opened them */
|
||||
if (input_file != stdin)
|
||||
fclose(input_file);
|
||||
if (output_file != stdout)
|
||||
fclose(output_file);
|
||||
|
||||
#ifdef PROGRESS_REPORT
|
||||
end_progress_monitor((j_common_ptr) &cinfo);
|
||||
#endif
|
||||
|
||||
/* All done. */
|
||||
exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);
|
||||
return 0; /* suppress no-return-value warnings */
|
||||
}
|
||||
|
|
@ -1,791 +0,0 @@
|
|||
/*
|
||||
* alternate cjpeg.c
|
||||
*
|
||||
* Copyright (C) 1991-1998, Thomas G. Lane.
|
||||
* Modified 2009-2023 by Guido Vollbeding.
|
||||
* 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 alternate user interface for the JPEG compressor.
|
||||
* One or more input files are named on the command line, and output file
|
||||
* names are created by substituting ".jpg" for the input file's extension.
|
||||
*/
|
||||
|
||||
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
||||
#include "jversion.h" /* for version message */
|
||||
|
||||
#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
|
||||
#ifdef __MWERKS__
|
||||
#include <SIOUX.h> /* Metrowerks needs this */
|
||||
#include <console.h> /* ... and this */
|
||||
#endif
|
||||
#ifdef THINK_C
|
||||
#include <console.h> /* Think declares it here */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef PATH_MAX /* ANSI maximum-pathname-length constant */
|
||||
#define PATH_MAX 256
|
||||
#endif
|
||||
|
||||
|
||||
/* Create the add-on message string table. */
|
||||
|
||||
#define JMESSAGE(code,string) string ,
|
||||
|
||||
static const char * const cdjpeg_message_table[] = {
|
||||
#include "cderror.h"
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Automatic determination of available memory.
|
||||
*/
|
||||
|
||||
static long default_maxmem; /* saves value determined at startup, or 0 */
|
||||
|
||||
#ifndef FREE_MEM_ESTIMATE /* may be defined from command line */
|
||||
|
||||
#ifdef MSDOS /* For MS-DOS (unless flat-memory model) */
|
||||
|
||||
#include <dos.h> /* for access to intdos() call */
|
||||
|
||||
LOCAL(long)
|
||||
unused_dos_memory (void)
|
||||
/* Obtain total amount of unallocated DOS memory */
|
||||
{
|
||||
union REGS regs;
|
||||
long nparas;
|
||||
|
||||
regs.h.ah = 0x48; /* DOS function Allocate Memory Block */
|
||||
regs.x.bx = 0xFFFF; /* Ask for more memory than DOS can have */
|
||||
(void) intdos(®s, ®s);
|
||||
/* DOS will fail and return # of paragraphs actually available in BX. */
|
||||
nparas = (unsigned int) regs.x.bx;
|
||||
/* Times 16 to convert to bytes. */
|
||||
return nparas << 4;
|
||||
}
|
||||
|
||||
/* The default memory setting is 95% of the available space. */
|
||||
#define FREE_MEM_ESTIMATE ((unused_dos_memory() * 95L) / 100L)
|
||||
|
||||
#endif /* MSDOS */
|
||||
|
||||
#ifdef ATARI /* For Atari ST/Mega/STE/TT/Falcon, Pure C or Turbo C */
|
||||
|
||||
#include <ext.h>
|
||||
|
||||
/* The default memory setting is 90% of the available space. */
|
||||
#define FREE_MEM_ESTIMATE (((long) coreleft() * 90L) / 100L)
|
||||
|
||||
#endif /* ATARI */
|
||||
|
||||
/* Add memory-estimation procedures for other operating systems here,
|
||||
* with appropriate #ifdef's around them.
|
||||
*/
|
||||
|
||||
#endif /* !FREE_MEM_ESTIMATE */
|
||||
|
||||
|
||||
/*
|
||||
* This routine determines what format the input file is,
|
||||
* and selects the appropriate input-reading module.
|
||||
*
|
||||
* To determine which family of input formats the file belongs to,
|
||||
* we may look only at the first byte of the file, since C does not
|
||||
* guarantee that more than one character can be pushed back with ungetc.
|
||||
* Looking at additional bytes would require one of these approaches:
|
||||
* 1) assume we can fseek() the input file (fails for piped input);
|
||||
* 2) assume we can push back more than one character (works in
|
||||
* some C implementations, but unportable);
|
||||
* 3) provide our own buffering (breaks input readers that want to use
|
||||
* stdio directly, such as the RLE library);
|
||||
* or 4) don't put back the data, and modify the input_init methods to assume
|
||||
* they start reading after the start of file (also breaks RLE library).
|
||||
* #1 is attractive for MS-DOS but is untenable on Unix.
|
||||
*
|
||||
* The most portable solution for file types that can't be identified by their
|
||||
* first byte is to make the user tell us what they are. This is also the
|
||||
* only approach for "raw" file types that contain only arbitrary values.
|
||||
* We presently apply this method for Targa files. Most of the time Targa
|
||||
* files start with 0x00, so we recognize that case. Potentially, however,
|
||||
* a Targa file could start with any byte value (byte 0 is the length of the
|
||||
* seldom-used ID field), so we provide a switch to force Targa input mode.
|
||||
*/
|
||||
|
||||
static boolean is_targa; /* records user -targa switch */
|
||||
|
||||
|
||||
LOCAL(cjpeg_source_ptr)
|
||||
select_file_type (j_compress_ptr cinfo, FILE * infile)
|
||||
{
|
||||
int c;
|
||||
|
||||
if (is_targa) {
|
||||
#ifdef TARGA_SUPPORTED
|
||||
return jinit_read_targa(cinfo);
|
||||
#else
|
||||
ERREXIT(cinfo, JERR_TGA_NOTCOMP);
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((c = getc(infile)) == EOF)
|
||||
ERREXIT(cinfo, JERR_INPUT_EMPTY);
|
||||
if (ungetc(c, infile) == EOF)
|
||||
ERREXIT(cinfo, JERR_UNGETC_FAILED);
|
||||
|
||||
switch (c) {
|
||||
#ifdef BMP_SUPPORTED
|
||||
case 'B':
|
||||
return jinit_read_bmp(cinfo);
|
||||
#endif
|
||||
#ifdef GIF_SUPPORTED
|
||||
case 'G':
|
||||
return jinit_read_gif(cinfo);
|
||||
#endif
|
||||
#ifdef PPM_SUPPORTED
|
||||
case 'P':
|
||||
return jinit_read_ppm(cinfo);
|
||||
#endif
|
||||
#ifdef RLE_SUPPORTED
|
||||
case 'R':
|
||||
return jinit_read_rle(cinfo);
|
||||
#endif
|
||||
#ifdef TARGA_SUPPORTED
|
||||
case 0x00:
|
||||
return jinit_read_targa(cinfo);
|
||||
#endif
|
||||
default:
|
||||
ERREXIT(cinfo, JERR_UNKNOWN_FORMAT);
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL; /* suppress compiler warnings */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Argument-parsing code.
|
||||
* The switch parser is designed to be useful with DOS-style command line
|
||||
* syntax, ie, intermixed switches and file names, where only the switches
|
||||
* to the left of a given file name affect processing of that file.
|
||||
*/
|
||||
|
||||
|
||||
static const char * progname; /* program name for error messages */
|
||||
static char * outfilename; /* for -outfile switch */
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
usage (void)
|
||||
/* complain about bad command line */
|
||||
{
|
||||
fprintf(stderr, "usage: %s [switches] inputfile(s)\n", progname);
|
||||
fprintf(stderr, "List of input files may use wildcards (* and ?)\n");
|
||||
fprintf(stderr, "Output filename is same as input filename, but extension .jpg\n");
|
||||
|
||||
fprintf(stderr, "Switches (names may be abbreviated):\n");
|
||||
fprintf(stderr, " -quality N[,...] Compression quality (0..100; 5-95 is useful range)\n");
|
||||
fprintf(stderr, " -grayscale Create monochrome JPEG file\n");
|
||||
fprintf(stderr, " -rgb Create RGB JPEG file\n");
|
||||
#ifdef ENTROPY_OPT_SUPPORTED
|
||||
fprintf(stderr, " -optimize Optimize Huffman table (smaller file, but slow compression)\n");
|
||||
#endif
|
||||
#ifdef C_PROGRESSIVE_SUPPORTED
|
||||
fprintf(stderr, " -progressive Create progressive JPEG file\n");
|
||||
#endif
|
||||
#ifdef DCT_SCALING_SUPPORTED
|
||||
fprintf(stderr, " -scale M/N Scale image by fraction M/N, eg, 1/2\n");
|
||||
#endif
|
||||
#ifdef TARGA_SUPPORTED
|
||||
fprintf(stderr, " -targa Input file is Targa format (usually not needed)\n");
|
||||
#endif
|
||||
fprintf(stderr, "Switches for advanced users:\n");
|
||||
#ifdef C_ARITH_CODING_SUPPORTED
|
||||
fprintf(stderr, " -arithmetic Use arithmetic coding\n");
|
||||
#endif
|
||||
#ifdef DCT_SCALING_SUPPORTED
|
||||
fprintf(stderr, " -block N DCT block size (1..16; default is 8)\n");
|
||||
#endif
|
||||
#if JPEG_LIB_VERSION_MAJOR >= 9
|
||||
fprintf(stderr, " -rgb1 Create RGB JPEG file with reversible color transform\n");
|
||||
fprintf(stderr, " -bgycc Create big gamut YCC JPEG file\n");
|
||||
#endif
|
||||
#ifdef DCT_ISLOW_SUPPORTED
|
||||
fprintf(stderr, " -dct int Use integer DCT method%s\n",
|
||||
(JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : ""));
|
||||
#endif
|
||||
#ifdef DCT_IFAST_SUPPORTED
|
||||
fprintf(stderr, " -dct fast Use fast integer DCT (less accurate)%s\n",
|
||||
(JDCT_DEFAULT == JDCT_IFAST ? " (default)" : ""));
|
||||
#endif
|
||||
#ifdef DCT_FLOAT_SUPPORTED
|
||||
fprintf(stderr, " -dct float Use floating-point DCT method%s\n",
|
||||
(JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : ""));
|
||||
#endif
|
||||
fprintf(stderr, " -nosmooth Don't use high-quality downsampling\n");
|
||||
fprintf(stderr, " -restart N Set restart interval in rows, or in blocks with B\n");
|
||||
#ifdef INPUT_SMOOTHING_SUPPORTED
|
||||
fprintf(stderr, " -smooth N Smooth dithered input (N=1..100 is strength)\n");
|
||||
#endif
|
||||
#ifndef FREE_MEM_ESTIMATE
|
||||
fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n");
|
||||
#endif
|
||||
fprintf(stderr, " -outfile name Specify name for output file\n");
|
||||
fprintf(stderr, " -verbose or -debug Emit debug output\n");
|
||||
fprintf(stderr, "Switches for wizards:\n");
|
||||
fprintf(stderr, " -baseline Force baseline quantization tables\n");
|
||||
fprintf(stderr, " -qtables file Use quantization tables given in file\n");
|
||||
fprintf(stderr, " -qslots N[,...] Set component quantization tables\n");
|
||||
fprintf(stderr, " -sample HxV[,...] Set component sampling factors\n");
|
||||
#ifdef C_MULTISCAN_FILES_SUPPORTED
|
||||
fprintf(stderr, " -scans file Create multi-scan JPEG per script file\n");
|
||||
#endif
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
LOCAL(int)
|
||||
parse_switches (j_compress_ptr cinfo, int argc, char **argv,
|
||||
int last_file_arg_seen, boolean for_real)
|
||||
/* Parse optional switches.
|
||||
* Returns argv[] index of first file-name argument (== argc if none).
|
||||
* Any file names with indexes <= last_file_arg_seen are ignored;
|
||||
* they have presumably been processed in a previous iteration.
|
||||
* (Pass 0 for last_file_arg_seen on the first or only iteration.)
|
||||
* for_real is FALSE on the first (dummy) pass; we may skip any expensive
|
||||
* processing.
|
||||
*/
|
||||
{
|
||||
int argn;
|
||||
char * arg;
|
||||
boolean force_baseline;
|
||||
boolean simple_progressive;
|
||||
char * qualityarg = NULL; /* saves -quality parm if any */
|
||||
char * qtablefile = NULL; /* saves -qtables filename if any */
|
||||
char * qslotsarg = NULL; /* saves -qslots parm if any */
|
||||
char * samplearg = NULL; /* saves -sample parm if any */
|
||||
char * scansarg = NULL; /* saves -scans parm if any */
|
||||
|
||||
/* Set up default JPEG parameters. */
|
||||
|
||||
force_baseline = FALSE; /* by default, allow 16-bit quantizers */
|
||||
simple_progressive = FALSE;
|
||||
is_targa = FALSE;
|
||||
outfilename = NULL;
|
||||
cinfo->err->trace_level = 0;
|
||||
if (default_maxmem > 0) /* override library's default value */
|
||||
cinfo->mem->max_memory_to_use = default_maxmem;
|
||||
|
||||
/* Scan command line options, adjust parameters */
|
||||
|
||||
for (argn = 1; argn < argc; argn++) {
|
||||
arg = argv[argn];
|
||||
if (*arg != '-') {
|
||||
/* Not a switch, must be a file name argument */
|
||||
if (argn <= last_file_arg_seen) {
|
||||
outfilename = NULL; /* -outfile applies to just one input file */
|
||||
continue; /* ignore this name if previously processed */
|
||||
}
|
||||
break; /* else done parsing switches */
|
||||
}
|
||||
arg++; /* advance past switch marker character */
|
||||
|
||||
if (keymatch(arg, "arithmetic", 1)) {
|
||||
/* Use arithmetic coding. */
|
||||
#ifdef C_ARITH_CODING_SUPPORTED
|
||||
cinfo->arith_code = TRUE;
|
||||
#else
|
||||
fprintf(stderr, "%s: sorry, arithmetic coding not supported\n",
|
||||
progname);
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
|
||||
} else if (keymatch(arg, "baseline", 2)) {
|
||||
/* Force baseline-compatible output (8-bit quantizer values). */
|
||||
force_baseline = TRUE;
|
||||
|
||||
} else if (keymatch(arg, "block", 2)) {
|
||||
/* Set DCT block size. */
|
||||
#if defined DCT_SCALING_SUPPORTED && JPEG_LIB_VERSION_MAJOR >= 8 && \
|
||||
(JPEG_LIB_VERSION_MAJOR > 8 || JPEG_LIB_VERSION_MINOR >= 3)
|
||||
int val;
|
||||
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (sscanf(argv[argn], "%d", &val) != 1)
|
||||
usage();
|
||||
if (val < 1 || val > 16)
|
||||
usage();
|
||||
cinfo->block_size = val;
|
||||
#else
|
||||
fprintf(stderr, "%s: sorry, block size setting not supported\n",
|
||||
progname);
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
|
||||
} else if (keymatch(arg, "dct", 2)) {
|
||||
/* Select DCT algorithm. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (keymatch(argv[argn], "int", 1)) {
|
||||
cinfo->dct_method = JDCT_ISLOW;
|
||||
} else if (keymatch(argv[argn], "fast", 2)) {
|
||||
cinfo->dct_method = JDCT_IFAST;
|
||||
} else if (keymatch(argv[argn], "float", 2)) {
|
||||
cinfo->dct_method = JDCT_FLOAT;
|
||||
} else
|
||||
usage();
|
||||
|
||||
} else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
|
||||
/* Enable debug printouts. */
|
||||
/* On first -d, print version identification */
|
||||
static boolean printed_version = FALSE;
|
||||
|
||||
if (! printed_version) {
|
||||
fprintf(stderr, "Independent JPEG Group's CJPEG, version %s\n%s\n",
|
||||
JVERSION, JCOPYRIGHT);
|
||||
printed_version = TRUE;
|
||||
}
|
||||
cinfo->err->trace_level++;
|
||||
|
||||
} else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) {
|
||||
/* Force a monochrome JPEG file to be generated. */
|
||||
jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
|
||||
|
||||
} else if (keymatch(arg, "rgb", 3) || keymatch(arg, "rgb1", 4)) {
|
||||
/* Force an RGB JPEG file to be generated. */
|
||||
#if JPEG_LIB_VERSION_MAJOR >= 9
|
||||
/* Note: Entropy table assignment in jpeg_set_colorspace depends
|
||||
* on color_transform.
|
||||
*/
|
||||
cinfo->color_transform = arg[3] ? JCT_SUBTRACT_GREEN : JCT_NONE;
|
||||
#endif
|
||||
jpeg_set_colorspace(cinfo, JCS_RGB);
|
||||
|
||||
} else if (keymatch(arg, "bgycc", 5)) {
|
||||
/* Force a big gamut YCC JPEG file to be generated. */
|
||||
#if JPEG_LIB_VERSION_MAJOR >= 9 && \
|
||||
(JPEG_LIB_VERSION_MAJOR > 9 || JPEG_LIB_VERSION_MINOR >= 1)
|
||||
jpeg_set_colorspace(cinfo, JCS_BG_YCC);
|
||||
#else
|
||||
fprintf(stderr, "%s: sorry, BG_YCC colorspace not supported\n",
|
||||
progname);
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
|
||||
} else if (keymatch(arg, "maxmemory", 3)) {
|
||||
/* Maximum memory in Kb (or Mb with 'm'). */
|
||||
long lval;
|
||||
char ch = 'x';
|
||||
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
|
||||
usage();
|
||||
if (ch == 'm' || ch == 'M')
|
||||
lval *= 1000L;
|
||||
cinfo->mem->max_memory_to_use = lval * 1000L;
|
||||
|
||||
} else if (keymatch(arg, "nosmooth", 3)) {
|
||||
/* Suppress fancy downsampling. */
|
||||
cinfo->do_fancy_downsampling = FALSE;
|
||||
|
||||
} else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) {
|
||||
/* Enable entropy parm optimization. */
|
||||
#ifdef ENTROPY_OPT_SUPPORTED
|
||||
cinfo->optimize_coding = TRUE;
|
||||
#else
|
||||
fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n",
|
||||
progname);
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
|
||||
} else if (keymatch(arg, "outfile", 4)) {
|
||||
/* Set output file name. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
outfilename = argv[argn]; /* save it away for later use */
|
||||
|
||||
} else if (keymatch(arg, "progressive", 1)) {
|
||||
/* Select simple progressive mode. */
|
||||
#ifdef C_PROGRESSIVE_SUPPORTED
|
||||
simple_progressive = TRUE;
|
||||
/* We must postpone execution until num_components is known. */
|
||||
#else
|
||||
fprintf(stderr, "%s: sorry, progressive output was not compiled\n",
|
||||
progname);
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
|
||||
} else if (keymatch(arg, "quality", 1)) {
|
||||
/* Quality ratings (quantization table scaling factors). */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
qualityarg = argv[argn];
|
||||
|
||||
} else if (keymatch(arg, "qslots", 2)) {
|
||||
/* Quantization table slot numbers. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
qslotsarg = argv[argn];
|
||||
/* Must delay setting qslots until after we have processed any
|
||||
* colorspace-determining switches, since jpeg_set_colorspace sets
|
||||
* default quant table numbers.
|
||||
*/
|
||||
|
||||
} else if (keymatch(arg, "qtables", 2)) {
|
||||
/* Quantization tables fetched from file. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
qtablefile = argv[argn];
|
||||
/* We postpone actually reading the file in case -quality comes later. */
|
||||
|
||||
} else if (keymatch(arg, "restart", 1)) {
|
||||
/* Restart interval in MCU rows (or in MCUs with 'b'). */
|
||||
long lval;
|
||||
char ch = 'x';
|
||||
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
|
||||
usage();
|
||||
if (lval < 0 || lval > 65535L)
|
||||
usage();
|
||||
if (ch == 'b' || ch == 'B') {
|
||||
cinfo->restart_interval = (unsigned int) lval;
|
||||
cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */
|
||||
} else {
|
||||
cinfo->restart_in_rows = (int) lval;
|
||||
/* restart_interval will be computed during startup */
|
||||
}
|
||||
|
||||
} else if (keymatch(arg, "sample", 2)) {
|
||||
/* Set sampling factors. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
samplearg = argv[argn];
|
||||
/* Must delay setting sample factors until after we have processed any
|
||||
* colorspace-determining switches, since jpeg_set_colorspace sets
|
||||
* default sampling factors.
|
||||
*/
|
||||
|
||||
} else if (keymatch(arg, "scale", 4)) {
|
||||
/* Scale the image by a fraction M/N. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (sscanf(argv[argn], "%d/%d",
|
||||
&cinfo->scale_num, &cinfo->scale_denom) != 2)
|
||||
usage();
|
||||
|
||||
} else if (keymatch(arg, "scans", 4)) {
|
||||
/* Set scan script. */
|
||||
#ifdef C_MULTISCAN_FILES_SUPPORTED
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
scansarg = argv[argn];
|
||||
/* We must postpone reading the file in case -progressive appears. */
|
||||
#else
|
||||
fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n",
|
||||
progname);
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
|
||||
} else if (keymatch(arg, "smooth", 2)) {
|
||||
/* Set input smoothing factor. */
|
||||
int val;
|
||||
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (sscanf(argv[argn], "%d", &val) != 1)
|
||||
usage();
|
||||
if (val < 0 || val > 100)
|
||||
usage();
|
||||
cinfo->smoothing_factor = val;
|
||||
|
||||
} else if (keymatch(arg, "targa", 1)) {
|
||||
/* Input file is Targa format. */
|
||||
is_targa = TRUE;
|
||||
|
||||
} else {
|
||||
usage(); /* bogus switch */
|
||||
}
|
||||
}
|
||||
|
||||
/* Post-switch-scanning cleanup */
|
||||
|
||||
if (for_real) {
|
||||
|
||||
/* Set quantization tables for selected quality. */
|
||||
/* Some or all may be overridden if -qtables is present. */
|
||||
if (qualityarg != NULL) /* process -quality if it was present */
|
||||
if (! set_quality_ratings(cinfo, qualityarg, force_baseline))
|
||||
usage();
|
||||
|
||||
if (qtablefile != NULL) /* process -qtables if it was present */
|
||||
if (! read_quant_tables(cinfo, qtablefile, force_baseline))
|
||||
usage();
|
||||
|
||||
if (qslotsarg != NULL) /* process -qslots if it was present */
|
||||
if (! set_quant_slots(cinfo, qslotsarg))
|
||||
usage();
|
||||
|
||||
if (samplearg != NULL) /* process -sample if it was present */
|
||||
if (! set_sample_factors(cinfo, samplearg))
|
||||
usage();
|
||||
|
||||
#ifdef C_PROGRESSIVE_SUPPORTED
|
||||
if (simple_progressive) /* process -progressive; -scans can override */
|
||||
jpeg_simple_progression(cinfo);
|
||||
#endif
|
||||
|
||||
#ifdef C_MULTISCAN_FILES_SUPPORTED
|
||||
if (scansarg != NULL) /* process -scans if it was present */
|
||||
if (! read_scan_script(cinfo, scansarg))
|
||||
usage();
|
||||
#endif
|
||||
}
|
||||
|
||||
return argn; /* return index of next arg (file name) */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check for overwrite of an existing file; clear it with user
|
||||
*/
|
||||
|
||||
#ifndef NO_OVERWRITE_CHECK
|
||||
|
||||
LOCAL(boolean)
|
||||
is_write_ok (char * outfname)
|
||||
{
|
||||
FILE * ofile;
|
||||
int ch;
|
||||
|
||||
ofile = fopen(outfname, 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] ",
|
||||
outfname);
|
||||
fflush(stderr);
|
||||
ch = getc(stdin);
|
||||
if (ch != '\n') /* flush rest of line */
|
||||
while (getc(stdin) != '\n')
|
||||
/* nothing */;
|
||||
|
||||
switch (ch) {
|
||||
case 'Y':
|
||||
case 'y':
|
||||
return TRUE;
|
||||
case 'N':
|
||||
case 'n':
|
||||
return FALSE;
|
||||
/* otherwise, ask again */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Process a single input file name, and return its index in argv[].
|
||||
* File names at or to left of old_file_index have been processed already.
|
||||
*/
|
||||
|
||||
LOCAL(int)
|
||||
process_one_file (int argc, char **argv, int old_file_index)
|
||||
{
|
||||
struct jpeg_compress_struct cinfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
char *infilename;
|
||||
char workfilename[PATH_MAX];
|
||||
#ifdef PROGRESS_REPORT
|
||||
struct cdjpeg_progress_mgr progress;
|
||||
#endif
|
||||
int file_index;
|
||||
cjpeg_source_ptr src_mgr;
|
||||
FILE * input_file = NULL;
|
||||
FILE * output_file = NULL;
|
||||
JDIMENSION num_scanlines;
|
||||
|
||||
/* Initialize the JPEG compression object with default error handling. */
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
jpeg_create_compress(&cinfo);
|
||||
/* Add some application-specific error messages (from cderror.h) */
|
||||
jerr.addon_message_table = cdjpeg_message_table;
|
||||
jerr.first_addon_message = JMSG_FIRSTADDONCODE;
|
||||
jerr.last_addon_message = JMSG_LASTADDONCODE;
|
||||
|
||||
/* Now safe to enable signal catcher. */
|
||||
#ifdef NEED_SIGNAL_CATCHER
|
||||
enable_signal_catcher((j_common_ptr) &cinfo);
|
||||
#endif
|
||||
|
||||
/* Initialize JPEG parameters.
|
||||
* Much of this may be overridden later.
|
||||
* In particular, we don't yet know the input file's color space,
|
||||
* but we need to provide some value for jpeg_set_defaults() to work.
|
||||
*/
|
||||
|
||||
cinfo.in_color_space = JCS_RGB; /* arbitrary guess */
|
||||
jpeg_set_defaults(&cinfo);
|
||||
|
||||
/* Scan command line to find next file name.
|
||||
* It is convenient to use just one switch-parsing routine, but the switch
|
||||
* values read here are ignored; we will rescan the switches after opening
|
||||
* the input file.
|
||||
*/
|
||||
|
||||
file_index = parse_switches(&cinfo, argc, argv, old_file_index, FALSE);
|
||||
if (file_index >= argc) {
|
||||
fprintf(stderr, "%s: missing input file name\n", progname);
|
||||
usage();
|
||||
}
|
||||
|
||||
/* Open the input file. */
|
||||
infilename = argv[file_index];
|
||||
if ((input_file = fopen(infilename, READ_BINARY)) == NULL) {
|
||||
fprintf(stderr, "%s: can't open %s\n", progname, infilename);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef PROGRESS_REPORT
|
||||
start_progress_monitor((j_common_ptr) &cinfo, &progress);
|
||||
#endif
|
||||
|
||||
/* Figure out the input file format, and set up to read it. */
|
||||
src_mgr = select_file_type(&cinfo, input_file);
|
||||
src_mgr->input_file = input_file;
|
||||
|
||||
/* Read the input file header to obtain file size & colorspace. */
|
||||
(*src_mgr->start_input) (&cinfo, src_mgr);
|
||||
|
||||
/* Now that we know input colorspace, fix colorspace-dependent defaults */
|
||||
jpeg_default_colorspace(&cinfo);
|
||||
|
||||
/* Adjust default compression parameters by re-parsing the options */
|
||||
file_index = parse_switches(&cinfo, argc, argv, old_file_index, TRUE);
|
||||
|
||||
/* If user didn't supply -outfile switch, select output file name. */
|
||||
if (outfilename == NULL) {
|
||||
int i;
|
||||
|
||||
outfilename = workfilename;
|
||||
/* Make outfilename be infilename with .jpg substituted for extension */
|
||||
strcpy(outfilename, infilename);
|
||||
for (i = (int)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 */
|
||||
}
|
||||
}
|
||||
strcat(outfilename, ".jpg");
|
||||
}
|
||||
|
||||
fprintf(stderr, "Compressing %s => %s\n", infilename, outfilename);
|
||||
#ifndef NO_OVERWRITE_CHECK
|
||||
if (! is_write_ok(outfilename))
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
/* Open the output file. */
|
||||
if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
|
||||
fprintf(stderr, "%s: can't create %s\n", progname, outfilename);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Specify data destination for compression */
|
||||
jpeg_stdio_dest(&cinfo, output_file);
|
||||
|
||||
/* Start compressor */
|
||||
jpeg_start_compress(&cinfo, TRUE);
|
||||
|
||||
/* Process data */
|
||||
while (cinfo.next_scanline < cinfo.image_height) {
|
||||
num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr);
|
||||
(void) jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines);
|
||||
}
|
||||
|
||||
/* Finish compression and release memory */
|
||||
(*src_mgr->finish_input) (&cinfo, src_mgr);
|
||||
jpeg_finish_compress(&cinfo);
|
||||
|
||||
/* Clean up and exit */
|
||||
fail:
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
|
||||
if (input_file != NULL) fclose(input_file);
|
||||
if (output_file != NULL) fclose(output_file);
|
||||
|
||||
#ifdef PROGRESS_REPORT
|
||||
end_progress_monitor((j_common_ptr) &cinfo);
|
||||
#endif
|
||||
|
||||
/* Disable signal catcher. */
|
||||
#ifdef NEED_SIGNAL_CATCHER
|
||||
enable_signal_catcher((j_common_ptr) NULL);
|
||||
#endif
|
||||
|
||||
return file_index;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The main program.
|
||||
*/
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int file_index;
|
||||
|
||||
/* On Mac, fetch a command line. */
|
||||
#ifdef USE_CCOMMAND
|
||||
argc = ccommand(&argv);
|
||||
#endif
|
||||
|
||||
#ifdef MSDOS
|
||||
progname = "cjpeg"; /* DOS tends to be too verbose about argv[0] */
|
||||
#else
|
||||
progname = argv[0];
|
||||
if (progname == NULL || progname[0] == 0)
|
||||
progname = "cjpeg"; /* in case C library doesn't provide it */
|
||||
#endif
|
||||
|
||||
/* The default maxmem must be computed only once at program startup,
|
||||
* since releasing memory with free() won't give it back to the OS.
|
||||
*/
|
||||
#ifdef FREE_MEM_ESTIMATE
|
||||
default_maxmem = FREE_MEM_ESTIMATE;
|
||||
#else
|
||||
default_maxmem = 0;
|
||||
#endif
|
||||
|
||||
/* Scan command line, parse switches and locate input file names */
|
||||
|
||||
if (argc < 2)
|
||||
usage(); /* nothing on the command line?? */
|
||||
|
||||
file_index = 0;
|
||||
|
||||
while (file_index < argc-1)
|
||||
file_index = process_one_file(argc, argv, file_index);
|
||||
|
||||
/* All done. */
|
||||
exit(EXIT_SUCCESS);
|
||||
return 0; /* suppress no-return-value warnings */
|
||||
}
|
||||
|
|
@ -1,402 +0,0 @@
|
|||
/*
|
||||
* ckconfig.c
|
||||
*
|
||||
* Copyright (C) 1991-1994, 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 program is intended to help you determine how to configure the JPEG
|
||||
* software for installation on a particular system. The idea is to try to
|
||||
* compile and execute this program. If your compiler fails to compile the
|
||||
* program, make changes as indicated in the comments below. Once you can
|
||||
* compile the program, run it, and it will produce a "jconfig.h" file for
|
||||
* your system.
|
||||
*
|
||||
* As a general rule, each time you try to compile this program,
|
||||
* pay attention only to the *first* error message you get from the compiler.
|
||||
* Many C compilers will issue lots of spurious error messages once they
|
||||
* have gotten confused. Go to the line indicated in the first error message,
|
||||
* and read the comments preceding that line to see what to change.
|
||||
*
|
||||
* Almost all of the edits you may need to make to this program consist of
|
||||
* changing a line that reads "#define SOME_SYMBOL" to "#undef SOME_SYMBOL",
|
||||
* or vice versa. This is called defining or undefining that symbol.
|
||||
*/
|
||||
|
||||
|
||||
/* First we must see if your system has the include files we need.
|
||||
* We start out with the assumption that your system has all the ANSI-standard
|
||||
* include files. If you get any error trying to include one of these files,
|
||||
* undefine the corresponding HAVE_xxx symbol.
|
||||
*/
|
||||
|
||||
#define HAVE_STDDEF_H /* replace 'define' by 'undef' if error here */
|
||||
#ifdef HAVE_STDDEF_H /* next line will be skipped if you undef... */
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
#define HAVE_STDLIB_H /* same thing for stdlib.h */
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h> /* If you ain't got this, you ain't got C. */
|
||||
|
||||
/* We have to see if your string functions are defined by
|
||||
* strings.h (old BSD convention) or string.h (everybody else).
|
||||
* We try the non-BSD convention first; define NEED_BSD_STRINGS
|
||||
* if the compiler says it can't find string.h.
|
||||
*/
|
||||
|
||||
#undef NEED_BSD_STRINGS
|
||||
|
||||
#ifdef NEED_BSD_STRINGS
|
||||
#include <strings.h>
|
||||
#else
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
/* On some systems (especially older Unix machines), type size_t is
|
||||
* defined only in the include file <sys/types.h>. If you get a failure
|
||||
* on the size_t test below, try defining NEED_SYS_TYPES_H.
|
||||
*/
|
||||
|
||||
#undef NEED_SYS_TYPES_H /* start by assuming we don't need it */
|
||||
#ifdef NEED_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* Usually type size_t is defined in one of the include files we've included
|
||||
* above. If not, you'll get an error on the "typedef size_t my_size_t;" line.
|
||||
* In that case, first try defining NEED_SYS_TYPES_H just above.
|
||||
* If that doesn't work, you'll have to search through your system library
|
||||
* to figure out which include file defines "size_t". Look for a line that
|
||||
* says "typedef something-or-other size_t;". Then, change the line below
|
||||
* that says "#include <someincludefile.h>" to instead include the file
|
||||
* you found size_t in, and define NEED_SPECIAL_INCLUDE. If you can't find
|
||||
* type size_t anywhere, try replacing "#include <someincludefile.h>" with
|
||||
* "typedef unsigned int size_t;".
|
||||
*/
|
||||
|
||||
#undef NEED_SPECIAL_INCLUDE /* assume we DON'T need it, for starters */
|
||||
|
||||
#ifdef NEED_SPECIAL_INCLUDE
|
||||
#include <someincludefile.h>
|
||||
#endif
|
||||
|
||||
typedef size_t my_size_t; /* The payoff: do we have size_t now? */
|
||||
|
||||
|
||||
/* The next question is whether your compiler supports ANSI-style function
|
||||
* prototypes. You need to know this in order to choose between using
|
||||
* makefile.ansi and using makefile.unix.
|
||||
* The #define line below is set to assume you have ANSI function prototypes.
|
||||
* If you get an error in this group of lines, undefine HAVE_PROTOTYPES.
|
||||
*/
|
||||
|
||||
#define HAVE_PROTOTYPES
|
||||
|
||||
#ifdef HAVE_PROTOTYPES
|
||||
int testfunction (int arg1, int * arg2); /* check prototypes */
|
||||
|
||||
struct methods_struct { /* check method-pointer declarations */
|
||||
int (*error_exit) (char *msgtext);
|
||||
int (*trace_message) (char *msgtext);
|
||||
int (*another_method) (void);
|
||||
};
|
||||
|
||||
int testfunction (int arg1, int * arg2) /* check definitions */
|
||||
{
|
||||
return arg2[arg1];
|
||||
}
|
||||
|
||||
int test2function (void) /* check void arg list */
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Now we want to find out if your compiler knows what "unsigned char" means.
|
||||
* If you get an error on the "unsigned char un_char;" line,
|
||||
* then undefine HAVE_UNSIGNED_CHAR.
|
||||
*/
|
||||
|
||||
#define HAVE_UNSIGNED_CHAR
|
||||
|
||||
#ifdef HAVE_UNSIGNED_CHAR
|
||||
unsigned char un_char;
|
||||
#endif
|
||||
|
||||
|
||||
/* Now we want to find out if your compiler knows what "unsigned short" means.
|
||||
* If you get an error on the "unsigned short un_short;" line,
|
||||
* then undefine HAVE_UNSIGNED_SHORT.
|
||||
*/
|
||||
|
||||
#define HAVE_UNSIGNED_SHORT
|
||||
|
||||
#ifdef HAVE_UNSIGNED_SHORT
|
||||
unsigned short un_short;
|
||||
#endif
|
||||
|
||||
|
||||
/* Now we want to find out if your compiler understands type "void".
|
||||
* If you get an error anywhere in here, undefine HAVE_VOID.
|
||||
*/
|
||||
|
||||
#define HAVE_VOID
|
||||
|
||||
#ifdef HAVE_VOID
|
||||
/* Caution: a C++ compiler will insist on complete prototypes */
|
||||
typedef void * void_ptr; /* check void * */
|
||||
#ifdef HAVE_PROTOTYPES /* check ptr to function returning void */
|
||||
typedef void (*void_func) (int a, int b);
|
||||
#else
|
||||
typedef void (*void_func) ();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PROTOTYPES /* check void function result */
|
||||
void test3function (void_ptr arg1, void_func arg2)
|
||||
#else
|
||||
void test3function (arg1, arg2)
|
||||
void_ptr arg1;
|
||||
void_func arg2;
|
||||
#endif
|
||||
{
|
||||
char * locptr = (char *) arg1; /* check casting to and from void * */
|
||||
arg1 = (void *) locptr;
|
||||
(*arg2) (1, 2); /* check call of fcn returning void */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Now we want to find out if your compiler knows what "const" means.
|
||||
* If you get an error here, undefine HAVE_CONST.
|
||||
*/
|
||||
|
||||
#define HAVE_CONST
|
||||
|
||||
#ifdef HAVE_CONST
|
||||
static const int carray[3] = {1, 2, 3};
|
||||
|
||||
#ifdef HAVE_PROTOTYPES
|
||||
int test4function (const int arg1)
|
||||
#else
|
||||
int test4function (arg1)
|
||||
const int arg1;
|
||||
#endif
|
||||
{
|
||||
return carray[arg1];
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* If you get an error or warning about this structure definition,
|
||||
* define INCOMPLETE_TYPES_BROKEN.
|
||||
*/
|
||||
|
||||
#undef INCOMPLETE_TYPES_BROKEN
|
||||
|
||||
#ifndef INCOMPLETE_TYPES_BROKEN
|
||||
typedef struct undefined_structure * undef_struct_ptr;
|
||||
#endif
|
||||
|
||||
|
||||
/* If you get an error about duplicate names,
|
||||
* define NEED_SHORT_EXTERNAL_NAMES.
|
||||
*/
|
||||
|
||||
#undef NEED_SHORT_EXTERNAL_NAMES
|
||||
|
||||
#ifndef NEED_SHORT_EXTERNAL_NAMES
|
||||
|
||||
int possibly_duplicate_function ()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int possibly_dupli_function ()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* OK, that's it. You should not have to change anything beyond this
|
||||
* point in order to compile and execute this program. (You might get
|
||||
* some warnings, but you can ignore them.)
|
||||
* When you run the program, it will make a couple more tests that it
|
||||
* can do automatically, and then it will create jconfig.h and print out
|
||||
* any additional suggestions it has.
|
||||
************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_PROTOTYPES
|
||||
int is_char_signed (int arg)
|
||||
#else
|
||||
int is_char_signed (arg)
|
||||
int arg;
|
||||
#endif
|
||||
{
|
||||
if (arg == 189) { /* expected result for unsigned char */
|
||||
return 0; /* type char is unsigned */
|
||||
}
|
||||
else if (arg != -67) { /* expected result for signed char */
|
||||
printf("Hmm, it seems 'char' is not eight bits wide on your machine.\n");
|
||||
printf("I fear the JPEG software will not work at all.\n\n");
|
||||
}
|
||||
return 1; /* assume char is signed otherwise */
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_PROTOTYPES
|
||||
int is_shifting_signed (long arg)
|
||||
#else
|
||||
int is_shifting_signed (arg)
|
||||
long arg;
|
||||
#endif
|
||||
/* See whether right-shift on a long is signed or not. */
|
||||
{
|
||||
long res = arg >> 4;
|
||||
|
||||
if (res == -0x7F7E80CL) { /* expected result for signed shift */
|
||||
return 1; /* right shift is signed */
|
||||
}
|
||||
/* see if unsigned-shift hack will fix it. */
|
||||
/* we can't just test exact value since it depends on width of long... */
|
||||
res |= (~0L) << (32-4);
|
||||
if (res == -0x7F7E80CL) { /* expected result now? */
|
||||
return 0; /* right shift is unsigned */
|
||||
}
|
||||
printf("Right shift isn't acting as I expect it to.\n");
|
||||
printf("I fear the JPEG software will not work at all.\n\n");
|
||||
return 0; /* try it with unsigned anyway */
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_PROTOTYPES
|
||||
int main (int argc, char ** argv)
|
||||
#else
|
||||
int main (argc, argv)
|
||||
int argc;
|
||||
char ** argv;
|
||||
#endif
|
||||
{
|
||||
char signed_char_check = (char) (-67);
|
||||
FILE *outfile;
|
||||
|
||||
/* Attempt to write jconfig.h */
|
||||
if ((outfile = fopen("jconfig.h", "w")) == NULL) {
|
||||
printf("Failed to write jconfig.h\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Write out all the info */
|
||||
fprintf(outfile, "/* jconfig.h --- generated by ckconfig.c */\n");
|
||||
fprintf(outfile, "/* see jconfig.txt for explanations */\n\n");
|
||||
#ifdef HAVE_PROTOTYPES
|
||||
fprintf(outfile, "#define HAVE_PROTOTYPES\n");
|
||||
#else
|
||||
fprintf(outfile, "#undef HAVE_PROTOTYPES\n");
|
||||
#endif
|
||||
#ifdef HAVE_UNSIGNED_CHAR
|
||||
fprintf(outfile, "#define HAVE_UNSIGNED_CHAR\n");
|
||||
#else
|
||||
fprintf(outfile, "#undef HAVE_UNSIGNED_CHAR\n");
|
||||
#endif
|
||||
#ifdef HAVE_UNSIGNED_SHORT
|
||||
fprintf(outfile, "#define HAVE_UNSIGNED_SHORT\n");
|
||||
#else
|
||||
fprintf(outfile, "#undef HAVE_UNSIGNED_SHORT\n");
|
||||
#endif
|
||||
#ifdef HAVE_VOID
|
||||
fprintf(outfile, "/* #define void char */\n");
|
||||
#else
|
||||
fprintf(outfile, "#define void char\n");
|
||||
#endif
|
||||
#ifdef HAVE_CONST
|
||||
fprintf(outfile, "/* #define const */\n");
|
||||
#else
|
||||
fprintf(outfile, "#define const\n");
|
||||
#endif
|
||||
if (is_char_signed((int) signed_char_check))
|
||||
fprintf(outfile, "#undef CHAR_IS_UNSIGNED\n");
|
||||
else
|
||||
fprintf(outfile, "#define CHAR_IS_UNSIGNED\n");
|
||||
#ifdef HAVE_STDDEF_H
|
||||
fprintf(outfile, "#define HAVE_STDDEF_H\n");
|
||||
#else
|
||||
fprintf(outfile, "#undef HAVE_STDDEF_H\n");
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
fprintf(outfile, "#define HAVE_STDLIB_H\n");
|
||||
#else
|
||||
fprintf(outfile, "#undef HAVE_STDLIB_H\n");
|
||||
#endif
|
||||
#ifdef NEED_BSD_STRINGS
|
||||
fprintf(outfile, "#define NEED_BSD_STRINGS\n");
|
||||
#else
|
||||
fprintf(outfile, "#undef NEED_BSD_STRINGS\n");
|
||||
#endif
|
||||
#ifdef NEED_SYS_TYPES_H
|
||||
fprintf(outfile, "#define NEED_SYS_TYPES_H\n");
|
||||
#else
|
||||
fprintf(outfile, "#undef NEED_SYS_TYPES_H\n");
|
||||
#endif
|
||||
fprintf(outfile, "#undef NEED_FAR_POINTERS\n");
|
||||
#ifdef NEED_SHORT_EXTERNAL_NAMES
|
||||
fprintf(outfile, "#define NEED_SHORT_EXTERNAL_NAMES\n");
|
||||
#else
|
||||
fprintf(outfile, "#undef NEED_SHORT_EXTERNAL_NAMES\n");
|
||||
#endif
|
||||
#ifdef INCOMPLETE_TYPES_BROKEN
|
||||
fprintf(outfile, "#define INCOMPLETE_TYPES_BROKEN\n");
|
||||
#else
|
||||
fprintf(outfile, "#undef INCOMPLETE_TYPES_BROKEN\n");
|
||||
#endif
|
||||
fprintf(outfile, "\n#ifdef JPEG_INTERNALS\n\n");
|
||||
if (is_shifting_signed(-0x7F7E80B1L))
|
||||
fprintf(outfile, "#undef RIGHT_SHIFT_IS_UNSIGNED\n");
|
||||
else
|
||||
fprintf(outfile, "#define RIGHT_SHIFT_IS_UNSIGNED\n");
|
||||
fprintf(outfile, "\n#endif /* JPEG_INTERNALS */\n");
|
||||
fprintf(outfile, "\n#ifdef JPEG_CJPEG_DJPEG\n\n");
|
||||
fprintf(outfile, "#define BMP_SUPPORTED /* BMP image file format */\n");
|
||||
fprintf(outfile, "#define GIF_SUPPORTED /* GIF image file format */\n");
|
||||
fprintf(outfile, "#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */\n");
|
||||
fprintf(outfile, "#undef RLE_SUPPORTED /* Utah RLE image file format */\n");
|
||||
fprintf(outfile, "#define TARGA_SUPPORTED /* Targa image file format */\n\n");
|
||||
fprintf(outfile, "#undef TWO_FILE_COMMANDLINE /* You may need this on non-Unix systems */\n");
|
||||
fprintf(outfile, "#undef NEED_SIGNAL_CATCHER /* Define this if you use jmemname.c */\n");
|
||||
fprintf(outfile, "#undef DONT_USE_B_MODE\n");
|
||||
fprintf(outfile, "/* #define PROGRESS_REPORT */ /* optional */\n");
|
||||
fprintf(outfile, "\n#endif /* JPEG_CJPEG_DJPEG */\n");
|
||||
|
||||
/* Close the jconfig.h file */
|
||||
fclose(outfile);
|
||||
|
||||
/* User report */
|
||||
printf("Configuration check for Independent JPEG Group's software done.\n");
|
||||
printf("\nI have written the jconfig.h file for you.\n\n");
|
||||
#ifdef HAVE_PROTOTYPES
|
||||
printf("You should use makefile.ansi as the starting point for your Makefile.\n");
|
||||
#else
|
||||
printf("You should use makefile.unix as the starting point for your Makefile.\n");
|
||||
#endif
|
||||
|
||||
#ifdef NEED_SPECIAL_INCLUDE
|
||||
printf("\nYou'll need to change jconfig.h to include the system include file\n");
|
||||
printf("that you found type size_t in, or add a direct definition of type\n");
|
||||
printf("size_t if that's what you used. Just add it to the end.\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,631 +0,0 @@
|
|||
/*
|
||||
* djpeg.c
|
||||
*
|
||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||
* Modified 2009-2019 by Guido Vollbeding.
|
||||
* 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 a command-line user interface for the JPEG decompressor.
|
||||
* It should work on any system with Unix- or MS-DOS-style command lines.
|
||||
*
|
||||
* Two different command line styles are permitted, depending on the
|
||||
* compile-time switch TWO_FILE_COMMANDLINE:
|
||||
* djpeg [options] inputfile outputfile
|
||||
* djpeg [options] [inputfile]
|
||||
* In the second style, output is always to standard output, which you'd
|
||||
* normally redirect to a file or pipe to some other program. Input is
|
||||
* either from a named file or from standard input (typically redirected).
|
||||
* The second style is convenient on Unix but is unhelpful on systems that
|
||||
* don't support pipes. Also, you MUST use the first style if your system
|
||||
* doesn't do binary I/O to stdin/stdout.
|
||||
* To simplify script writing, the "-outfile" switch is provided. The syntax
|
||||
* djpeg [options] -outfile outputfile inputfile
|
||||
* works regardless of which command line style is used.
|
||||
*/
|
||||
|
||||
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
||||
#include "jversion.h" /* for version message */
|
||||
|
||||
#include <ctype.h> /* to declare isprint() */
|
||||
|
||||
#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
|
||||
#ifdef __MWERKS__
|
||||
#include <SIOUX.h> /* Metrowerks needs this */
|
||||
#include <console.h> /* ... and this */
|
||||
#endif
|
||||
#ifdef THINK_C
|
||||
#include <console.h> /* Think declares it here */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* Create the add-on message string table. */
|
||||
|
||||
#define JMESSAGE(code,string) string ,
|
||||
|
||||
static const char * const cdjpeg_message_table[] = {
|
||||
#include "cderror.h"
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* 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 PPM_SUPPORTED.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
FMT_BMP, /* BMP format (Windows flavor) */
|
||||
FMT_GIF, /* GIF format (LZW compressed) */
|
||||
FMT_GIF0, /* GIF format (uncompressed) */
|
||||
FMT_OS2, /* BMP format (OS/2 flavor) */
|
||||
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_PPM
|
||||
#endif
|
||||
|
||||
static IMAGE_FORMATS requested_fmt;
|
||||
|
||||
|
||||
/*
|
||||
* Argument-parsing code.
|
||||
* The switch parser is designed to be useful with DOS-style command line
|
||||
* syntax, ie, intermixed switches and file names, where only the switches
|
||||
* to the left of a given file name affect processing of that file.
|
||||
* The main program in this file doesn't actually use this capability...
|
||||
*/
|
||||
|
||||
|
||||
static const char * progname; /* program name for error messages */
|
||||
static char * outfilename; /* for -outfile switch */
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
usage (void)
|
||||
/* complain about bad command line */
|
||||
{
|
||||
fprintf(stderr, "usage: %s [switches] ", progname);
|
||||
#ifdef TWO_FILE_COMMANDLINE
|
||||
fprintf(stderr, "inputfile outputfile\n");
|
||||
#else
|
||||
fprintf(stderr, "[inputfile]\n");
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "Switches (names may be abbreviated):\n");
|
||||
fprintf(stderr, " -colors N Reduce image to no more than N colors\n");
|
||||
fprintf(stderr, " -fast Fast, low-quality processing\n");
|
||||
fprintf(stderr, " -grayscale Force grayscale output\n");
|
||||
fprintf(stderr, " -rgb Force RGB output\n");
|
||||
#ifdef IDCT_SCALING_SUPPORTED
|
||||
fprintf(stderr, " -scale M/N Scale output image by fraction M/N, eg, 1/8\n");
|
||||
#endif
|
||||
#ifdef BMP_SUPPORTED
|
||||
fprintf(stderr, " -bmp Select BMP output format (Windows style)%s\n",
|
||||
(DEFAULT_FMT == FMT_BMP ? " (default)" : ""));
|
||||
#endif
|
||||
#ifdef GIF_SUPPORTED
|
||||
fprintf(stderr, " -gif Select GIF output format (LZW compressed)%s\n",
|
||||
(DEFAULT_FMT == FMT_GIF ? " (default)" : ""));
|
||||
fprintf(stderr, " -gif0 Select GIF output format (uncompressed)%s\n",
|
||||
(DEFAULT_FMT == FMT_GIF0 ? " (default)" : ""));
|
||||
#endif
|
||||
#ifdef BMP_SUPPORTED
|
||||
fprintf(stderr, " -os2 Select BMP output format (OS/2 style)%s\n",
|
||||
(DEFAULT_FMT == FMT_OS2 ? " (default)" : ""));
|
||||
#endif
|
||||
#ifdef PPM_SUPPORTED
|
||||
fprintf(stderr, " -pnm Select PBMPLUS (PPM/PGM) output format%s\n",
|
||||
(DEFAULT_FMT == FMT_PPM ? " (default)" : ""));
|
||||
#endif
|
||||
#ifdef RLE_SUPPORTED
|
||||
fprintf(stderr, " -rle Select Utah RLE output format%s\n",
|
||||
(DEFAULT_FMT == FMT_RLE ? " (default)" : ""));
|
||||
#endif
|
||||
#ifdef TARGA_SUPPORTED
|
||||
fprintf(stderr, " -targa Select Targa output format%s\n",
|
||||
(DEFAULT_FMT == FMT_TARGA ? " (default)" : ""));
|
||||
#endif
|
||||
fprintf(stderr, "Switches for advanced users:\n");
|
||||
#ifdef DCT_ISLOW_SUPPORTED
|
||||
fprintf(stderr, " -dct int Use integer DCT method%s\n",
|
||||
(JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : ""));
|
||||
#endif
|
||||
#ifdef DCT_IFAST_SUPPORTED
|
||||
fprintf(stderr, " -dct fast Use fast integer DCT (less accurate)%s\n",
|
||||
(JDCT_DEFAULT == JDCT_IFAST ? " (default)" : ""));
|
||||
#endif
|
||||
#ifdef DCT_FLOAT_SUPPORTED
|
||||
fprintf(stderr, " -dct float Use floating-point DCT method%s\n",
|
||||
(JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : ""));
|
||||
#endif
|
||||
fprintf(stderr, " -dither fs Use F-S dithering (default)\n");
|
||||
fprintf(stderr, " -dither none Don't use dithering in quantization\n");
|
||||
fprintf(stderr, " -dither ordered Use ordered dither (medium speed, quality)\n");
|
||||
#ifdef QUANT_2PASS_SUPPORTED
|
||||
fprintf(stderr, " -map FILE Map to colors used in named image file\n");
|
||||
#endif
|
||||
fprintf(stderr, " -nosmooth Don't use high-quality upsampling\n");
|
||||
#ifdef QUANT_1PASS_SUPPORTED
|
||||
fprintf(stderr, " -onepass Use 1-pass quantization (fast, low quality)\n");
|
||||
#endif
|
||||
fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n");
|
||||
fprintf(stderr, " -outfile name Specify name for output file\n");
|
||||
fprintf(stderr, " -verbose or -debug Emit debug output\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
LOCAL(int)
|
||||
parse_switches (j_decompress_ptr cinfo, int argc, char **argv,
|
||||
int last_file_arg_seen, boolean for_real)
|
||||
/* Parse optional switches.
|
||||
* Returns argv[] index of first file-name argument (== argc if none).
|
||||
* Any file names with indexes <= last_file_arg_seen are ignored;
|
||||
* they have presumably been processed in a previous iteration.
|
||||
* (Pass 0 for last_file_arg_seen on the first or only iteration.)
|
||||
* for_real is FALSE on the first (dummy) pass; we may skip any expensive
|
||||
* processing.
|
||||
*/
|
||||
{
|
||||
int argn;
|
||||
char * arg;
|
||||
|
||||
/* Set up default JPEG parameters. */
|
||||
requested_fmt = DEFAULT_FMT; /* set default output file format */
|
||||
outfilename = NULL;
|
||||
cinfo->err->trace_level = 0;
|
||||
|
||||
/* Scan command line options, adjust parameters */
|
||||
|
||||
for (argn = 1; argn < argc; argn++) {
|
||||
arg = argv[argn];
|
||||
if (*arg != '-') {
|
||||
/* Not a switch, must be a file name argument */
|
||||
if (argn <= last_file_arg_seen) {
|
||||
outfilename = NULL; /* -outfile applies to just one input file */
|
||||
continue; /* ignore this name if previously processed */
|
||||
}
|
||||
break; /* else done parsing switches */
|
||||
}
|
||||
arg++; /* advance past switch marker character */
|
||||
|
||||
if (keymatch(arg, "bmp", 1)) {
|
||||
/* BMP output format (Windows flavor). */
|
||||
requested_fmt = FMT_BMP;
|
||||
|
||||
} else if (keymatch(arg, "colors", 1) || keymatch(arg, "colours", 1) ||
|
||||
keymatch(arg, "quantize", 1) || keymatch(arg, "quantise", 1)) {
|
||||
/* Do color quantization. */
|
||||
int val;
|
||||
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (sscanf(argv[argn], "%d", &val) != 1)
|
||||
usage();
|
||||
cinfo->desired_number_of_colors = val;
|
||||
cinfo->quantize_colors = TRUE;
|
||||
|
||||
} else if (keymatch(arg, "dct", 2)) {
|
||||
/* Select IDCT algorithm. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (keymatch(argv[argn], "int", 1)) {
|
||||
cinfo->dct_method = JDCT_ISLOW;
|
||||
} else if (keymatch(argv[argn], "fast", 2)) {
|
||||
cinfo->dct_method = JDCT_IFAST;
|
||||
} else if (keymatch(argv[argn], "float", 2)) {
|
||||
cinfo->dct_method = JDCT_FLOAT;
|
||||
} else
|
||||
usage();
|
||||
|
||||
} else if (keymatch(arg, "dither", 2)) {
|
||||
/* Select dithering algorithm. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (keymatch(argv[argn], "fs", 2)) {
|
||||
cinfo->dither_mode = JDITHER_FS;
|
||||
} else if (keymatch(argv[argn], "none", 2)) {
|
||||
cinfo->dither_mode = JDITHER_NONE;
|
||||
} else if (keymatch(argv[argn], "ordered", 2)) {
|
||||
cinfo->dither_mode = JDITHER_ORDERED;
|
||||
} else
|
||||
usage();
|
||||
|
||||
} else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
|
||||
/* Enable debug printouts. */
|
||||
/* On first -d, print version identification */
|
||||
static boolean printed_version = FALSE;
|
||||
|
||||
if (! printed_version) {
|
||||
fprintf(stderr, "Independent JPEG Group's DJPEG, version %s\n%s\n",
|
||||
JVERSION, JCOPYRIGHT);
|
||||
printed_version = TRUE;
|
||||
}
|
||||
cinfo->err->trace_level++;
|
||||
|
||||
} else if (keymatch(arg, "fast", 1)) {
|
||||
/* Select recommended processing options for quick-and-dirty output. */
|
||||
cinfo->two_pass_quantize = FALSE;
|
||||
cinfo->dither_mode = JDITHER_ORDERED;
|
||||
if (! cinfo->quantize_colors) /* don't override an earlier -colors */
|
||||
cinfo->desired_number_of_colors = 216;
|
||||
cinfo->dct_method = JDCT_FASTEST;
|
||||
cinfo->do_fancy_upsampling = FALSE;
|
||||
|
||||
} else if (keymatch(arg, "gif", 1)) {
|
||||
/* GIF output format (LZW compressed). */
|
||||
requested_fmt = FMT_GIF;
|
||||
|
||||
} else if (keymatch(arg, "gif0", 4)) {
|
||||
/* GIF output format (uncompressed). */
|
||||
requested_fmt = FMT_GIF0;
|
||||
|
||||
} else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) {
|
||||
/* Force monochrome output. */
|
||||
cinfo->out_color_space = JCS_GRAYSCALE;
|
||||
|
||||
} else if (keymatch(arg, "rgb", 3)) {
|
||||
/* Force RGB output. */
|
||||
cinfo->out_color_space = JCS_RGB;
|
||||
|
||||
} else if (keymatch(arg, "map", 3)) {
|
||||
/* Quantize to a color map taken from an input file. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (for_real) { /* too expensive to do twice! */
|
||||
#ifdef QUANT_2PASS_SUPPORTED /* otherwise can't quantize to supplied map */
|
||||
FILE * mapfile;
|
||||
|
||||
if ((mapfile = fopen(argv[argn], READ_BINARY)) == NULL) {
|
||||
fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
read_color_map(cinfo, mapfile);
|
||||
fclose(mapfile);
|
||||
cinfo->quantize_colors = TRUE;
|
||||
#else
|
||||
ERREXIT(cinfo, JERR_NOT_COMPILED);
|
||||
#endif
|
||||
}
|
||||
|
||||
} else if (keymatch(arg, "maxmemory", 3)) {
|
||||
/* Maximum memory in Kb (or Mb with 'm'). */
|
||||
long lval;
|
||||
char ch = 'x';
|
||||
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
|
||||
usage();
|
||||
if (ch == 'm' || ch == 'M')
|
||||
lval *= 1000L;
|
||||
cinfo->mem->max_memory_to_use = lval * 1000L;
|
||||
|
||||
} else if (keymatch(arg, "nosmooth", 3)) {
|
||||
/* Suppress fancy upsampling. */
|
||||
cinfo->do_fancy_upsampling = FALSE;
|
||||
|
||||
} else if (keymatch(arg, "onepass", 3)) {
|
||||
/* Use fast one-pass quantization. */
|
||||
cinfo->two_pass_quantize = FALSE;
|
||||
|
||||
} else if (keymatch(arg, "os2", 3)) {
|
||||
/* BMP output format (OS/2 flavor). */
|
||||
requested_fmt = FMT_OS2;
|
||||
|
||||
} else if (keymatch(arg, "outfile", 4)) {
|
||||
/* Set output file name. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
outfilename = argv[argn]; /* save it away for later use */
|
||||
|
||||
} else if (keymatch(arg, "pnm", 1) || keymatch(arg, "ppm", 1)) {
|
||||
/* PPM/PGM output format. */
|
||||
requested_fmt = FMT_PPM;
|
||||
|
||||
} else if (keymatch(arg, "rle", 1)) {
|
||||
/* RLE output format. */
|
||||
requested_fmt = FMT_RLE;
|
||||
|
||||
} else if (keymatch(arg, "scale", 1)) {
|
||||
/* Scale the output image by a fraction M/N. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (sscanf(argv[argn], "%u/%u",
|
||||
&cinfo->scale_num, &cinfo->scale_denom) < 1)
|
||||
usage();
|
||||
|
||||
} else if (keymatch(arg, "targa", 1)) {
|
||||
/* Targa output format. */
|
||||
requested_fmt = FMT_TARGA;
|
||||
|
||||
} else {
|
||||
usage(); /* bogus switch */
|
||||
}
|
||||
}
|
||||
|
||||
return argn; /* return index of next arg (file name) */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Marker processor for COM and interesting APPn markers.
|
||||
* This replaces the library's built-in processor, which just skips the marker.
|
||||
* We want to print out the marker as text, to the extent possible.
|
||||
* Note this code relies on a non-suspending data source.
|
||||
*/
|
||||
|
||||
LOCAL(unsigned int)
|
||||
jpeg_getc (j_decompress_ptr cinfo)
|
||||
/* Read next byte */
|
||||
{
|
||||
struct jpeg_source_mgr * datasrc = cinfo->src;
|
||||
|
||||
if (datasrc->bytes_in_buffer == 0) {
|
||||
if (! (*datasrc->fill_input_buffer) (cinfo))
|
||||
ERREXIT(cinfo, JERR_CANT_SUSPEND);
|
||||
}
|
||||
datasrc->bytes_in_buffer--;
|
||||
return GETJOCTET(*datasrc->next_input_byte++);
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(boolean)
|
||||
print_text_marker (j_decompress_ptr cinfo)
|
||||
{
|
||||
boolean traceit = (cinfo->err->trace_level >= 1);
|
||||
INT32 length;
|
||||
unsigned int ch;
|
||||
unsigned int lastch = 0;
|
||||
|
||||
length = jpeg_getc(cinfo) << 8;
|
||||
length += jpeg_getc(cinfo);
|
||||
length -= 2; /* discount the length word itself */
|
||||
|
||||
if (traceit) {
|
||||
if (cinfo->unread_marker == JPEG_COM)
|
||||
fprintf(stderr, "Comment, length %ld:\n", (long) length);
|
||||
else /* assume it is an APPn otherwise */
|
||||
fprintf(stderr, "APP%d, length %ld:\n",
|
||||
cinfo->unread_marker - JPEG_APP0, (long) length);
|
||||
}
|
||||
|
||||
while (--length >= 0) {
|
||||
ch = jpeg_getc(cinfo);
|
||||
if (traceit) {
|
||||
/* Emit the character in a readable form.
|
||||
* Nonprintables are converted to \nnn form,
|
||||
* while \ is converted to \\.
|
||||
* Newlines in CR, CR/LF, or LF form will be printed as one newline.
|
||||
*/
|
||||
if (ch == '\r') {
|
||||
fprintf(stderr, "\n");
|
||||
} else if (ch == '\n') {
|
||||
if (lastch != '\r')
|
||||
fprintf(stderr, "\n");
|
||||
} else if (ch == '\\') {
|
||||
fprintf(stderr, "\\\\");
|
||||
} else if (isprint(ch)) {
|
||||
putc(ch, stderr);
|
||||
} else {
|
||||
fprintf(stderr, "\\%03o", ch);
|
||||
}
|
||||
lastch = ch;
|
||||
}
|
||||
}
|
||||
|
||||
if (traceit)
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The main program.
|
||||
*/
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
struct jpeg_decompress_struct cinfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
#ifdef PROGRESS_REPORT
|
||||
struct cdjpeg_progress_mgr progress;
|
||||
#endif
|
||||
int file_index;
|
||||
djpeg_dest_ptr dest_mgr = NULL;
|
||||
FILE * input_file;
|
||||
FILE * output_file;
|
||||
JDIMENSION num_scanlines;
|
||||
|
||||
/* On Mac, fetch a command line. */
|
||||
#ifdef USE_CCOMMAND
|
||||
argc = ccommand(&argv);
|
||||
#endif
|
||||
|
||||
progname = argv[0];
|
||||
if (progname == NULL || progname[0] == 0)
|
||||
progname = "djpeg"; /* in case C library doesn't provide it */
|
||||
|
||||
/* Initialize the JPEG decompression object with default error handling. */
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
jpeg_create_decompress(&cinfo);
|
||||
/* Add some application-specific error messages (from cderror.h) */
|
||||
jerr.addon_message_table = cdjpeg_message_table;
|
||||
jerr.first_addon_message = JMSG_FIRSTADDONCODE;
|
||||
jerr.last_addon_message = JMSG_LASTADDONCODE;
|
||||
|
||||
/* Insert custom marker processor for COM and APP12.
|
||||
* APP12 is used by some digital camera makers for textual info,
|
||||
* so we provide the ability to display it as text.
|
||||
* If you like, additional APPn marker types can be selected for display,
|
||||
* but don't try to override APP0 or APP14 this way (see libjpeg.txt).
|
||||
*/
|
||||
jpeg_set_marker_processor(&cinfo, JPEG_COM, print_text_marker);
|
||||
jpeg_set_marker_processor(&cinfo, JPEG_APP0+12, print_text_marker);
|
||||
|
||||
/* Now safe to enable signal catcher. */
|
||||
#ifdef NEED_SIGNAL_CATCHER
|
||||
enable_signal_catcher((j_common_ptr) &cinfo);
|
||||
#endif
|
||||
|
||||
/* Scan command line to find file names. */
|
||||
/* It is convenient to use just one switch-parsing routine, but the switch
|
||||
* values read here are ignored; we will rescan the switches after opening
|
||||
* the input file.
|
||||
* (Exception: tracing level set here controls verbosity for COM markers
|
||||
* found during jpeg_read_header...)
|
||||
*/
|
||||
|
||||
file_index = parse_switches(&cinfo, argc, argv, 0, FALSE);
|
||||
|
||||
#ifdef TWO_FILE_COMMANDLINE
|
||||
/* Must have either -outfile switch or explicit output file name */
|
||||
if (outfilename == NULL) {
|
||||
if (file_index != argc-2) {
|
||||
fprintf(stderr, "%s: must name one input and one output file\n",
|
||||
progname);
|
||||
usage();
|
||||
}
|
||||
outfilename = argv[file_index+1];
|
||||
} else {
|
||||
if (file_index != argc-1) {
|
||||
fprintf(stderr, "%s: must name one input and one output file\n",
|
||||
progname);
|
||||
usage();
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* Unix style: expect zero or one file name */
|
||||
if (file_index < argc-1) {
|
||||
fprintf(stderr, "%s: only one input file\n", progname);
|
||||
usage();
|
||||
}
|
||||
#endif /* TWO_FILE_COMMANDLINE */
|
||||
|
||||
/* Open the input file. */
|
||||
if (file_index < argc) {
|
||||
if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
|
||||
fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
/* default input file is stdin */
|
||||
input_file = read_stdin();
|
||||
}
|
||||
|
||||
/* Open the output file. */
|
||||
if (outfilename != NULL) {
|
||||
if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
|
||||
fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
/* default output file is stdout */
|
||||
output_file = write_stdout();
|
||||
}
|
||||
|
||||
#ifdef PROGRESS_REPORT
|
||||
start_progress_monitor((j_common_ptr) &cinfo, &progress);
|
||||
#endif
|
||||
|
||||
/* Specify data source for decompression */
|
||||
jpeg_stdio_src(&cinfo, input_file);
|
||||
|
||||
/* Read file header, set default decompression parameters */
|
||||
(void) jpeg_read_header(&cinfo, TRUE);
|
||||
|
||||
/* Adjust default decompression parameters by re-parsing the options */
|
||||
file_index = parse_switches(&cinfo, argc, argv, 0, TRUE);
|
||||
|
||||
/* Initialize the output module now to let it override any crucial
|
||||
* option settings (for instance, GIF wants to force color quantization).
|
||||
*/
|
||||
switch (requested_fmt) {
|
||||
#ifdef BMP_SUPPORTED
|
||||
case FMT_BMP:
|
||||
dest_mgr = jinit_write_bmp(&cinfo, FALSE);
|
||||
break;
|
||||
case FMT_OS2:
|
||||
dest_mgr = jinit_write_bmp(&cinfo, TRUE);
|
||||
break;
|
||||
#endif
|
||||
#ifdef GIF_SUPPORTED
|
||||
case FMT_GIF:
|
||||
dest_mgr = jinit_write_gif(&cinfo, TRUE);
|
||||
break;
|
||||
case FMT_GIF0:
|
||||
dest_mgr = jinit_write_gif(&cinfo, FALSE);
|
||||
break;
|
||||
#endif
|
||||
#ifdef PPM_SUPPORTED
|
||||
case FMT_PPM:
|
||||
dest_mgr = jinit_write_ppm(&cinfo);
|
||||
break;
|
||||
#endif
|
||||
#ifdef RLE_SUPPORTED
|
||||
case FMT_RLE:
|
||||
dest_mgr = jinit_write_rle(&cinfo);
|
||||
break;
|
||||
#endif
|
||||
#ifdef TARGA_SUPPORTED
|
||||
case FMT_TARGA:
|
||||
dest_mgr = jinit_write_targa(&cinfo);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT);
|
||||
}
|
||||
dest_mgr->output_file = output_file;
|
||||
|
||||
/* Start decompressor */
|
||||
(void) jpeg_start_decompress(&cinfo);
|
||||
|
||||
/* Write output file header */
|
||||
(*dest_mgr->start_output) (&cinfo, dest_mgr);
|
||||
|
||||
/* Process data */
|
||||
while (cinfo.output_scanline < cinfo.output_height) {
|
||||
num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
|
||||
dest_mgr->buffer_height);
|
||||
(*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
|
||||
}
|
||||
|
||||
#ifdef PROGRESS_REPORT
|
||||
/* Hack: count final pass as done in case finish_output does an extra pass.
|
||||
* The library won't have updated completed_passes.
|
||||
*/
|
||||
progress.pub.completed_passes = progress.pub.total_passes;
|
||||
#endif
|
||||
|
||||
/* Finish decompression and release memory.
|
||||
* I must do it in this order because output module has allocated memory
|
||||
* of lifespan JPOOL_IMAGE; it needs to finish before releasing memory.
|
||||
*/
|
||||
(*dest_mgr->finish_output) (&cinfo, dest_mgr);
|
||||
(void) jpeg_finish_decompress(&cinfo);
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
|
||||
/* Close files, if we opened them */
|
||||
if (input_file != stdin)
|
||||
fclose(input_file);
|
||||
if (output_file != stdout)
|
||||
fclose(output_file);
|
||||
|
||||
#ifdef PROGRESS_REPORT
|
||||
end_progress_monitor((j_common_ptr) &cinfo);
|
||||
#endif
|
||||
|
||||
/* All done. */
|
||||
exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);
|
||||
return 0; /* suppress no-return-value warnings */
|
||||
}
|
||||
|
|
@ -1,766 +0,0 @@
|
|||
/*
|
||||
* alternate djpeg.c
|
||||
*
|
||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||
* Modified 2009-2023 by Guido Vollbeding.
|
||||
* 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 alternate user interface for the JPEG decompressor.
|
||||
* One or more input files are named on the command line, and output file
|
||||
* names are created by substituting an appropriate extension.
|
||||
*/
|
||||
|
||||
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
||||
#include "jversion.h" /* for version message */
|
||||
|
||||
#include <ctype.h> /* to declare isprint() */
|
||||
|
||||
#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
|
||||
#ifdef __MWERKS__
|
||||
#include <SIOUX.h> /* Metrowerks needs this */
|
||||
#include <console.h> /* ... and this */
|
||||
#endif
|
||||
#ifdef THINK_C
|
||||
#include <console.h> /* Think declares it here */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef PATH_MAX /* ANSI maximum-pathname-length constant */
|
||||
#define PATH_MAX 256
|
||||
#endif
|
||||
|
||||
|
||||
/* Create the add-on message string table. */
|
||||
|
||||
#define JMESSAGE(code,string) string ,
|
||||
|
||||
static const char * const cdjpeg_message_table[] = {
|
||||
#include "cderror.h"
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Automatic determination of available memory.
|
||||
*/
|
||||
|
||||
static long default_maxmem; /* saves value determined at startup, or 0 */
|
||||
|
||||
#ifndef FREE_MEM_ESTIMATE /* may be defined from command line */
|
||||
|
||||
#ifdef MSDOS /* For MS-DOS (unless flat-memory model) */
|
||||
|
||||
#include <dos.h> /* for access to intdos() call */
|
||||
|
||||
LOCAL(long)
|
||||
unused_dos_memory (void)
|
||||
/* Obtain total amount of unallocated DOS memory */
|
||||
{
|
||||
union REGS regs;
|
||||
long nparas;
|
||||
|
||||
regs.h.ah = 0x48; /* DOS function Allocate Memory Block */
|
||||
regs.x.bx = 0xFFFF; /* Ask for more memory than DOS can have */
|
||||
(void) intdos(®s, ®s);
|
||||
/* DOS will fail and return # of paragraphs actually available in BX. */
|
||||
nparas = (unsigned int) regs.x.bx;
|
||||
/* Times 16 to convert to bytes. */
|
||||
return nparas << 4;
|
||||
}
|
||||
|
||||
/* The default memory setting is 95% of the available space. */
|
||||
#define FREE_MEM_ESTIMATE ((unused_dos_memory() * 95L) / 100L)
|
||||
|
||||
#endif /* MSDOS */
|
||||
|
||||
#ifdef ATARI /* For Atari ST/Mega/STE/TT/Falcon, Pure C or Turbo C */
|
||||
|
||||
#include <ext.h>
|
||||
|
||||
/* The default memory setting is 90% of the available space. */
|
||||
#define FREE_MEM_ESTIMATE (((long) coreleft() * 90L) / 100L)
|
||||
|
||||
#endif /* ATARI */
|
||||
|
||||
/* Add memory-estimation procedures for other operating systems here,
|
||||
* with appropriate #ifdef's around them.
|
||||
*/
|
||||
|
||||
#endif /* !FREE_MEM_ESTIMATE */
|
||||
|
||||
|
||||
/*
|
||||
* 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 PPM_SUPPORTED.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
FMT_BMP, /* BMP format (Windows flavor) */
|
||||
FMT_GIF, /* GIF format (LZW compressed) */
|
||||
FMT_GIF0, /* GIF format (uncompressed) */
|
||||
FMT_OS2, /* BMP format (OS/2 flavor) */
|
||||
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_BMP
|
||||
#endif
|
||||
|
||||
static IMAGE_FORMATS requested_fmt;
|
||||
|
||||
|
||||
/*
|
||||
* Argument-parsing code.
|
||||
* The switch parser is designed to be useful with DOS-style command line
|
||||
* syntax, ie, intermixed switches and file names, where only the switches
|
||||
* to the left of a given file name affect processing of that file.
|
||||
*/
|
||||
|
||||
|
||||
static const char * progname; /* program name for error messages */
|
||||
static char * outfilename; /* for -outfile switch */
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
usage (void)
|
||||
/* complain about bad command line */
|
||||
{
|
||||
fprintf(stderr, "usage: %s [switches] inputfile(s)\n", progname);
|
||||
fprintf(stderr, "List of input files may use wildcards (* and ?)\n");
|
||||
fprintf(stderr, "Output filename is same as input filename except for extension\n");
|
||||
|
||||
fprintf(stderr, "Switches (names may be abbreviated):\n");
|
||||
fprintf(stderr, " -colors N Reduce image to no more than N colors\n");
|
||||
fprintf(stderr, " -fast Fast, low-quality processing\n");
|
||||
fprintf(stderr, " -grayscale Force grayscale output\n");
|
||||
fprintf(stderr, " -rgb Force RGB output\n");
|
||||
#ifdef IDCT_SCALING_SUPPORTED
|
||||
fprintf(stderr, " -scale M/N Scale output image by fraction M/N, eg, 1/8\n");
|
||||
#endif
|
||||
#ifdef BMP_SUPPORTED
|
||||
fprintf(stderr, " -bmp Select BMP output format (Windows style)%s\n",
|
||||
(DEFAULT_FMT == FMT_BMP ? " (default)" : ""));
|
||||
#endif
|
||||
#ifdef GIF_SUPPORTED
|
||||
fprintf(stderr, " -gif Select GIF output format (LZW compressed)%s\n",
|
||||
(DEFAULT_FMT == FMT_GIF ? " (default)" : ""));
|
||||
fprintf(stderr, " -gif0 Select GIF output format (uncompressed)%s\n",
|
||||
(DEFAULT_FMT == FMT_GIF0 ? " (default)" : ""));
|
||||
#endif
|
||||
#ifdef BMP_SUPPORTED
|
||||
fprintf(stderr, " -os2 Select BMP output format (OS/2 style)%s\n",
|
||||
(DEFAULT_FMT == FMT_OS2 ? " (default)" : ""));
|
||||
#endif
|
||||
#ifdef PPM_SUPPORTED
|
||||
fprintf(stderr, " -pnm Select PBMPLUS (PPM/PGM) output format%s\n",
|
||||
(DEFAULT_FMT == FMT_PPM ? " (default)" : ""));
|
||||
#endif
|
||||
#ifdef RLE_SUPPORTED
|
||||
fprintf(stderr, " -rle Select Utah RLE output format%s\n",
|
||||
(DEFAULT_FMT == FMT_RLE ? " (default)" : ""));
|
||||
#endif
|
||||
#ifdef TARGA_SUPPORTED
|
||||
fprintf(stderr, " -targa Select Targa output format%s\n",
|
||||
(DEFAULT_FMT == FMT_TARGA ? " (default)" : ""));
|
||||
#endif
|
||||
fprintf(stderr, "Switches for advanced users:\n");
|
||||
#ifdef DCT_ISLOW_SUPPORTED
|
||||
fprintf(stderr, " -dct int Use integer DCT method%s\n",
|
||||
(JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : ""));
|
||||
#endif
|
||||
#ifdef DCT_IFAST_SUPPORTED
|
||||
fprintf(stderr, " -dct fast Use fast integer DCT (less accurate)%s\n",
|
||||
(JDCT_DEFAULT == JDCT_IFAST ? " (default)" : ""));
|
||||
#endif
|
||||
#ifdef DCT_FLOAT_SUPPORTED
|
||||
fprintf(stderr, " -dct float Use floating-point DCT method%s\n",
|
||||
(JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : ""));
|
||||
#endif
|
||||
fprintf(stderr, " -dither fs Use F-S dithering (default)\n");
|
||||
fprintf(stderr, " -dither none Don't use dithering in quantization\n");
|
||||
fprintf(stderr, " -dither ordered Use ordered dither (medium speed, quality)\n");
|
||||
#ifdef QUANT_2PASS_SUPPORTED
|
||||
fprintf(stderr, " -map FILE Map to colors used in named image file\n");
|
||||
#endif
|
||||
fprintf(stderr, " -nosmooth Don't use high-quality upsampling\n");
|
||||
#ifdef QUANT_1PASS_SUPPORTED
|
||||
fprintf(stderr, " -onepass Use 1-pass quantization (fast, low quality)\n");
|
||||
#endif
|
||||
#ifndef FREE_MEM_ESTIMATE
|
||||
fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n");
|
||||
#endif
|
||||
fprintf(stderr, " -outfile name Specify name for output file\n");
|
||||
fprintf(stderr, " -verbose or -debug Emit debug output\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
LOCAL(int)
|
||||
parse_switches (j_decompress_ptr cinfo, int argc, char **argv,
|
||||
int last_file_arg_seen, boolean for_real)
|
||||
/* Parse optional switches.
|
||||
* Returns argv[] index of first file-name argument (== argc if none).
|
||||
* Any file names with indexes <= last_file_arg_seen are ignored;
|
||||
* they have presumably been processed in a previous iteration.
|
||||
* (Pass 0 for last_file_arg_seen on the first or only iteration.)
|
||||
* for_real is FALSE on the first (dummy) pass; we may skip any expensive
|
||||
* processing.
|
||||
*/
|
||||
{
|
||||
int argn;
|
||||
char * arg;
|
||||
|
||||
/* Set up default JPEG parameters. */
|
||||
requested_fmt = DEFAULT_FMT; /* set default output file format */
|
||||
outfilename = NULL;
|
||||
cinfo->err->trace_level = 0;
|
||||
if (default_maxmem > 0) /* override library's default value */
|
||||
cinfo->mem->max_memory_to_use = default_maxmem;
|
||||
|
||||
/* Scan command line options, adjust parameters */
|
||||
|
||||
for (argn = 1; argn < argc; argn++) {
|
||||
arg = argv[argn];
|
||||
if (*arg != '-') {
|
||||
/* Not a switch, must be a file name argument */
|
||||
if (argn <= last_file_arg_seen) {
|
||||
outfilename = NULL; /* -outfile applies to just one input file */
|
||||
continue; /* ignore this name if previously processed */
|
||||
}
|
||||
break; /* else done parsing switches */
|
||||
}
|
||||
arg++; /* advance past switch marker character */
|
||||
|
||||
if (keymatch(arg, "bmp", 1)) {
|
||||
/* BMP output format (Windows flavor). */
|
||||
requested_fmt = FMT_BMP;
|
||||
|
||||
} else if (keymatch(arg, "colors", 1) || keymatch(arg, "colours", 1) ||
|
||||
keymatch(arg, "quantize", 1) || keymatch(arg, "quantise", 1)) {
|
||||
/* Do color quantization. */
|
||||
int val;
|
||||
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (sscanf(argv[argn], "%d", &val) != 1)
|
||||
usage();
|
||||
cinfo->desired_number_of_colors = val;
|
||||
cinfo->quantize_colors = TRUE;
|
||||
|
||||
} else if (keymatch(arg, "dct", 2)) {
|
||||
/* Select IDCT algorithm. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (keymatch(argv[argn], "int", 1)) {
|
||||
cinfo->dct_method = JDCT_ISLOW;
|
||||
} else if (keymatch(argv[argn], "fast", 2)) {
|
||||
cinfo->dct_method = JDCT_IFAST;
|
||||
} else if (keymatch(argv[argn], "float", 2)) {
|
||||
cinfo->dct_method = JDCT_FLOAT;
|
||||
} else
|
||||
usage();
|
||||
|
||||
} else if (keymatch(arg, "dither", 2)) {
|
||||
/* Select dithering algorithm. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (keymatch(argv[argn], "fs", 2)) {
|
||||
cinfo->dither_mode = JDITHER_FS;
|
||||
} else if (keymatch(argv[argn], "none", 2)) {
|
||||
cinfo->dither_mode = JDITHER_NONE;
|
||||
} else if (keymatch(argv[argn], "ordered", 2)) {
|
||||
cinfo->dither_mode = JDITHER_ORDERED;
|
||||
} else
|
||||
usage();
|
||||
|
||||
} else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
|
||||
/* Enable debug printouts. */
|
||||
/* On first -d, print version identification */
|
||||
static boolean printed_version = FALSE;
|
||||
|
||||
if (! printed_version) {
|
||||
fprintf(stderr, "Independent JPEG Group's DJPEG, version %s\n%s\n",
|
||||
JVERSION, JCOPYRIGHT);
|
||||
printed_version = TRUE;
|
||||
}
|
||||
cinfo->err->trace_level++;
|
||||
|
||||
} else if (keymatch(arg, "fast", 1)) {
|
||||
/* Select recommended processing options for quick-and-dirty output. */
|
||||
cinfo->two_pass_quantize = FALSE;
|
||||
cinfo->dither_mode = JDITHER_ORDERED;
|
||||
if (! cinfo->quantize_colors) /* don't override an earlier -colors */
|
||||
cinfo->desired_number_of_colors = 216;
|
||||
cinfo->dct_method = JDCT_FASTEST;
|
||||
cinfo->do_fancy_upsampling = FALSE;
|
||||
|
||||
} else if (keymatch(arg, "gif", 1)) {
|
||||
/* GIF output format (LZW compressed). */
|
||||
requested_fmt = FMT_GIF;
|
||||
|
||||
} else if (keymatch(arg, "gif0", 4)) {
|
||||
/* GIF output format (uncompressed). */
|
||||
requested_fmt = FMT_GIF0;
|
||||
|
||||
} else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) {
|
||||
/* Force monochrome output. */
|
||||
cinfo->out_color_space = JCS_GRAYSCALE;
|
||||
|
||||
} else if (keymatch(arg, "rgb", 3)) {
|
||||
/* Force RGB output. */
|
||||
cinfo->out_color_space = JCS_RGB;
|
||||
|
||||
} else if (keymatch(arg, "map", 3)) {
|
||||
/* Quantize to a color map taken from an input file. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (for_real) { /* too expensive to do twice! */
|
||||
#ifdef QUANT_2PASS_SUPPORTED /* otherwise can't quantize to supplied map */
|
||||
FILE * mapfile;
|
||||
|
||||
if ((mapfile = fopen(argv[argn], READ_BINARY)) == NULL) {
|
||||
fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
read_color_map(cinfo, mapfile);
|
||||
fclose(mapfile);
|
||||
cinfo->quantize_colors = TRUE;
|
||||
#else
|
||||
ERREXIT(cinfo, JERR_NOT_COMPILED);
|
||||
#endif
|
||||
}
|
||||
|
||||
} else if (keymatch(arg, "maxmemory", 3)) {
|
||||
/* Maximum memory in Kb (or Mb with 'm'). */
|
||||
long lval;
|
||||
char ch = 'x';
|
||||
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
|
||||
usage();
|
||||
if (ch == 'm' || ch == 'M')
|
||||
lval *= 1000L;
|
||||
cinfo->mem->max_memory_to_use = lval * 1000L;
|
||||
|
||||
} else if (keymatch(arg, "nosmooth", 3)) {
|
||||
/* Suppress fancy upsampling. */
|
||||
cinfo->do_fancy_upsampling = FALSE;
|
||||
|
||||
} else if (keymatch(arg, "onepass", 3)) {
|
||||
/* Use fast one-pass quantization. */
|
||||
cinfo->two_pass_quantize = FALSE;
|
||||
|
||||
} else if (keymatch(arg, "os2", 3)) {
|
||||
/* BMP output format (OS/2 flavor). */
|
||||
requested_fmt = FMT_OS2;
|
||||
|
||||
} else if (keymatch(arg, "outfile", 4)) {
|
||||
/* Set output file name. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
outfilename = argv[argn]; /* save it away for later use */
|
||||
|
||||
} else if (keymatch(arg, "pnm", 1) || keymatch(arg, "ppm", 1)) {
|
||||
/* PPM/PGM output format. */
|
||||
requested_fmt = FMT_PPM;
|
||||
|
||||
} else if (keymatch(arg, "rle", 1)) {
|
||||
/* RLE output format. */
|
||||
requested_fmt = FMT_RLE;
|
||||
|
||||
} else if (keymatch(arg, "scale", 1)) {
|
||||
/* Scale the output image by a fraction M/N. */
|
||||
if (++argn >= argc) /* advance to next argument */
|
||||
usage();
|
||||
if (sscanf(argv[argn], "%u/%u",
|
||||
&cinfo->scale_num, &cinfo->scale_denom) < 1)
|
||||
usage();
|
||||
|
||||
} else if (keymatch(arg, "targa", 1)) {
|
||||
/* Targa output format. */
|
||||
requested_fmt = FMT_TARGA;
|
||||
|
||||
} else {
|
||||
usage(); /* bogus switch */
|
||||
}
|
||||
}
|
||||
|
||||
return argn; /* return index of next arg (file name) */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Marker processor for COM and interesting APPn markers.
|
||||
* This replaces the library's built-in processor, which just skips the marker.
|
||||
* We want to print out the marker as text, to the extent possible.
|
||||
* Note this code relies on a non-suspending data source.
|
||||
*/
|
||||
|
||||
LOCAL(unsigned int)
|
||||
jpeg_getc (j_decompress_ptr cinfo)
|
||||
/* Read next byte */
|
||||
{
|
||||
struct jpeg_source_mgr * datasrc = cinfo->src;
|
||||
|
||||
if (datasrc->bytes_in_buffer == 0) {
|
||||
if (! (*datasrc->fill_input_buffer) (cinfo))
|
||||
ERREXIT(cinfo, JERR_CANT_SUSPEND);
|
||||
}
|
||||
datasrc->bytes_in_buffer--;
|
||||
return GETJOCTET(*datasrc->next_input_byte++);
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(boolean)
|
||||
print_text_marker (j_decompress_ptr cinfo)
|
||||
{
|
||||
boolean traceit = (cinfo->err->trace_level >= 1);
|
||||
INT32 length;
|
||||
unsigned int ch;
|
||||
unsigned int lastch = 0;
|
||||
|
||||
length = jpeg_getc(cinfo) << 8;
|
||||
length += jpeg_getc(cinfo);
|
||||
length -= 2; /* discount the length word itself */
|
||||
|
||||
if (traceit) {
|
||||
if (cinfo->unread_marker == JPEG_COM)
|
||||
fprintf(stderr, "Comment, length %ld:\n", (long) length);
|
||||
else /* assume it is an APPn otherwise */
|
||||
fprintf(stderr, "APP%d, length %ld:\n",
|
||||
cinfo->unread_marker - JPEG_APP0, (long) length);
|
||||
}
|
||||
|
||||
while (--length >= 0) {
|
||||
ch = jpeg_getc(cinfo);
|
||||
if (traceit) {
|
||||
/* Emit the character in a readable form.
|
||||
* Nonprintables are converted to \nnn form,
|
||||
* while \ is converted to \\.
|
||||
* Newlines in CR, CR/LF, or LF form will be printed as one newline.
|
||||
*/
|
||||
if (ch == '\r') {
|
||||
fprintf(stderr, "\n");
|
||||
} else if (ch == '\n') {
|
||||
if (lastch != '\r')
|
||||
fprintf(stderr, "\n");
|
||||
} else if (ch == '\\') {
|
||||
fprintf(stderr, "\\\\");
|
||||
} else if (isprint(ch)) {
|
||||
putc(ch, stderr);
|
||||
} else {
|
||||
fprintf(stderr, "\\%03o", ch);
|
||||
}
|
||||
lastch = ch;
|
||||
}
|
||||
}
|
||||
|
||||
if (traceit)
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check for overwrite of an existing file; clear it with user
|
||||
*/
|
||||
|
||||
#ifndef NO_OVERWRITE_CHECK
|
||||
|
||||
LOCAL(boolean)
|
||||
is_write_ok (char * outfname)
|
||||
{
|
||||
FILE * ofile;
|
||||
int ch;
|
||||
|
||||
ofile = fopen(outfname, 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] ",
|
||||
outfname);
|
||||
fflush(stderr);
|
||||
ch = getc(stdin);
|
||||
if (ch != '\n') /* flush rest of line */
|
||||
while (getc(stdin) != '\n')
|
||||
/* nothing */;
|
||||
|
||||
switch (ch) {
|
||||
case 'Y':
|
||||
case 'y':
|
||||
return TRUE;
|
||||
case 'N':
|
||||
case 'n':
|
||||
return FALSE;
|
||||
/* otherwise, ask again */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Process a single input file name, and return its index in argv[].
|
||||
* File names at or to left of old_file_index have been processed already.
|
||||
*/
|
||||
|
||||
LOCAL(int)
|
||||
process_one_file (int argc, char **argv, int old_file_index)
|
||||
{
|
||||
struct jpeg_decompress_struct cinfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
char *infilename;
|
||||
char workfilename[PATH_MAX];
|
||||
const char *default_extension = NULL;
|
||||
#ifdef PROGRESS_REPORT
|
||||
struct cdjpeg_progress_mgr progress;
|
||||
#endif
|
||||
int file_index;
|
||||
djpeg_dest_ptr dest_mgr = NULL;
|
||||
FILE * input_file = NULL;
|
||||
FILE * output_file = NULL;
|
||||
JDIMENSION num_scanlines;
|
||||
|
||||
/* Initialize the JPEG decompression object with default error handling. */
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
jpeg_create_decompress(&cinfo);
|
||||
/* Add some application-specific error messages (from cderror.h) */
|
||||
jerr.addon_message_table = cdjpeg_message_table;
|
||||
jerr.first_addon_message = JMSG_FIRSTADDONCODE;
|
||||
jerr.last_addon_message = JMSG_LASTADDONCODE;
|
||||
|
||||
/* Insert custom marker processor for COM and APP12.
|
||||
* APP12 is used by some digital camera makers for textual info,
|
||||
* so we provide the ability to display it as text.
|
||||
* If you like, additional APPn marker types can be selected for display,
|
||||
* but don't try to override APP0 or APP14 this way (see libjpeg.txt).
|
||||
*/
|
||||
jpeg_set_marker_processor(&cinfo, JPEG_COM, print_text_marker);
|
||||
jpeg_set_marker_processor(&cinfo, JPEG_APP0+12, print_text_marker);
|
||||
|
||||
/* Now safe to enable signal catcher. */
|
||||
#ifdef NEED_SIGNAL_CATCHER
|
||||
enable_signal_catcher((j_common_ptr) &cinfo);
|
||||
#endif
|
||||
|
||||
/* Scan command line to find next file name.
|
||||
* It is convenient to use just one switch-parsing routine, but the switch
|
||||
* values read here are ignored; we will rescan the switches after opening
|
||||
* the input file.
|
||||
* (Exception: tracing level set here controls verbosity for COM markers
|
||||
* found during jpeg_read_header...)
|
||||
*/
|
||||
|
||||
file_index = parse_switches(&cinfo, argc, argv, old_file_index, FALSE);
|
||||
if (file_index >= argc) {
|
||||
fprintf(stderr, "%s: missing input file name\n", progname);
|
||||
usage();
|
||||
}
|
||||
|
||||
/* Open the input file. */
|
||||
infilename = argv[file_index];
|
||||
if ((input_file = fopen(infilename, READ_BINARY)) == NULL) {
|
||||
fprintf(stderr, "%s: can't open %s\n", progname, infilename);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef PROGRESS_REPORT
|
||||
start_progress_monitor((j_common_ptr) &cinfo, &progress);
|
||||
#endif
|
||||
|
||||
/* Specify data source for decompression */
|
||||
jpeg_stdio_src(&cinfo, input_file);
|
||||
|
||||
/* Read file header, set default decompression parameters */
|
||||
(void) jpeg_read_header(&cinfo, TRUE);
|
||||
|
||||
/* Adjust default decompression parameters by re-parsing the options */
|
||||
file_index = parse_switches(&cinfo, argc, argv, old_file_index, TRUE);
|
||||
|
||||
/* Initialize the output module now to let it override any crucial
|
||||
* option settings (for instance, GIF wants to force color quantization).
|
||||
*/
|
||||
switch (requested_fmt) {
|
||||
#ifdef BMP_SUPPORTED
|
||||
case FMT_BMP:
|
||||
dest_mgr = jinit_write_bmp(&cinfo, FALSE);
|
||||
default_extension = ".bmp";
|
||||
break;
|
||||
case FMT_OS2:
|
||||
dest_mgr = jinit_write_bmp(&cinfo, TRUE);
|
||||
default_extension = ".bmp";
|
||||
break;
|
||||
#endif
|
||||
#ifdef GIF_SUPPORTED
|
||||
case FMT_GIF:
|
||||
dest_mgr = jinit_write_gif(&cinfo, TRUE);
|
||||
default_extension = ".gif";
|
||||
break;
|
||||
case FMT_GIF0:
|
||||
dest_mgr = jinit_write_gif(&cinfo, FALSE);
|
||||
default_extension = ".gif";
|
||||
break;
|
||||
#endif
|
||||
#ifdef PPM_SUPPORTED
|
||||
case FMT_PPM:
|
||||
dest_mgr = jinit_write_ppm(&cinfo);
|
||||
default_extension = ".ppm";
|
||||
break;
|
||||
#endif
|
||||
#ifdef RLE_SUPPORTED
|
||||
case FMT_RLE:
|
||||
dest_mgr = jinit_write_rle(&cinfo);
|
||||
default_extension = ".rle";
|
||||
break;
|
||||
#endif
|
||||
#ifdef TARGA_SUPPORTED
|
||||
case FMT_TARGA:
|
||||
dest_mgr = jinit_write_targa(&cinfo);
|
||||
default_extension = ".tga";
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT);
|
||||
}
|
||||
|
||||
/* If user didn't supply -outfile switch, select output file name. */
|
||||
if (outfilename == NULL) {
|
||||
int i;
|
||||
|
||||
outfilename = workfilename;
|
||||
/* Make outfilename be infilename with appropriate extension */
|
||||
strcpy(outfilename, infilename);
|
||||
for (i = (int)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 */
|
||||
}
|
||||
}
|
||||
strcat(outfilename, default_extension);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Decompressing %s => %s\n", infilename, outfilename);
|
||||
#ifndef NO_OVERWRITE_CHECK
|
||||
if (! is_write_ok(outfilename))
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
/* Open the output file. */
|
||||
if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
|
||||
fprintf(stderr, "%s: can't create %s\n", progname, outfilename);
|
||||
goto fail;
|
||||
}
|
||||
dest_mgr->output_file = output_file;
|
||||
|
||||
/* Start decompressor */
|
||||
(void) jpeg_start_decompress(&cinfo);
|
||||
|
||||
/* Write output file header */
|
||||
(*dest_mgr->start_output) (&cinfo, dest_mgr);
|
||||
|
||||
/* Process data */
|
||||
while (cinfo.output_scanline < cinfo.output_height) {
|
||||
num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
|
||||
dest_mgr->buffer_height);
|
||||
(*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
|
||||
}
|
||||
|
||||
#ifdef PROGRESS_REPORT
|
||||
/* Hack: count final pass as done in case finish_output does an extra pass.
|
||||
* The library won't have updated completed_passes.
|
||||
*/
|
||||
progress.pub.completed_passes = progress.pub.total_passes;
|
||||
#endif
|
||||
|
||||
/* Finish decompression and release memory.
|
||||
* I must do it in this order because output module has allocated memory
|
||||
* of lifespan JPOOL_IMAGE; it needs to finish before releasing memory.
|
||||
*/
|
||||
(*dest_mgr->finish_output) (&cinfo, dest_mgr);
|
||||
(void) jpeg_finish_decompress(&cinfo);
|
||||
|
||||
/* Clean up and exit */
|
||||
fail:
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
|
||||
if (input_file != NULL) fclose(input_file);
|
||||
if (output_file != NULL) fclose(output_file);
|
||||
|
||||
#ifdef PROGRESS_REPORT
|
||||
end_progress_monitor((j_common_ptr) &cinfo);
|
||||
#endif
|
||||
|
||||
/* Disable signal catcher. */
|
||||
#ifdef NEED_SIGNAL_CATCHER
|
||||
enable_signal_catcher((j_common_ptr) NULL);
|
||||
#endif
|
||||
|
||||
return file_index;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The main program.
|
||||
*/
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int file_index;
|
||||
|
||||
/* On Mac, fetch a command line. */
|
||||
#ifdef USE_CCOMMAND
|
||||
argc = ccommand(&argv);
|
||||
#endif
|
||||
|
||||
#ifdef MSDOS
|
||||
progname = "djpeg"; /* DOS tends to be too verbose about argv[0] */
|
||||
#else
|
||||
progname = argv[0];
|
||||
if (progname == NULL || progname[0] == 0)
|
||||
progname = "djpeg"; /* in case C library doesn't provide it */
|
||||
#endif
|
||||
|
||||
/* The default maxmem must be computed only once at program startup,
|
||||
* since releasing memory with free() won't give it back to the OS.
|
||||
*/
|
||||
#ifdef FREE_MEM_ESTIMATE
|
||||
default_maxmem = FREE_MEM_ESTIMATE;
|
||||
#else
|
||||
default_maxmem = 0;
|
||||
#endif
|
||||
|
||||
/* Scan command line, parse switches and locate input file names */
|
||||
|
||||
if (argc < 2)
|
||||
usage(); /* nothing on the command line?? */
|
||||
|
||||
file_index = 0;
|
||||
|
||||
while (file_index < argc-1)
|
||||
file_index = process_one_file(argc, argv, file_index);
|
||||
|
||||
/* All done. */
|
||||
exit(EXIT_SUCCESS);
|
||||
return 0; /* suppress no-return-value warnings */
|
||||
}
|
||||
|
|
@ -1,433 +0,0 @@
|
|||
/*
|
||||
* example.c
|
||||
*
|
||||
* This file illustrates how to use the IJG code as a subroutine library
|
||||
* to read or write JPEG image files. You should look at this code in
|
||||
* conjunction with the documentation file libjpeg.txt.
|
||||
*
|
||||
* This code will not do anything useful as-is, but it may be helpful as a
|
||||
* skeleton for constructing routines that call the JPEG library.
|
||||
*
|
||||
* We present these routines in the same coding style used in the JPEG code
|
||||
* (ANSI function definitions, etc); but you are of course free to code your
|
||||
* routines in a different style if you prefer.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
* Include file for users of JPEG library.
|
||||
* You will need to have included system headers that define at least
|
||||
* the typedefs FILE and size_t before you can include jpeglib.h.
|
||||
* (stdio.h is sufficient on ANSI-conforming systems.)
|
||||
* You may also wish to include "jerror.h".
|
||||
*/
|
||||
|
||||
#include "jpeglib.h"
|
||||
|
||||
/*
|
||||
* <setjmp.h> is used for the optional error recovery mechanism shown in
|
||||
* the second part of the example.
|
||||
*/
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
|
||||
|
||||
/******************** JPEG COMPRESSION SAMPLE INTERFACE *******************/
|
||||
|
||||
/* This half of the example shows how to feed data into the JPEG compressor.
|
||||
* We present a minimal version that does not worry about refinements such
|
||||
* as error recovery (the JPEG code will just exit() if it gets an error).
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* IMAGE DATA FORMATS:
|
||||
*
|
||||
* The standard input image format is a rectangular array of pixels, with
|
||||
* each pixel having the same number of "component" values (color channels).
|
||||
* Each pixel row is an array of JSAMPLEs (which typically are unsigned chars).
|
||||
* If you are working with color data, then the color values for each pixel
|
||||
* must be adjacent in the row; for example, R,G,B,R,G,B,R,G,B,... for 24-bit
|
||||
* RGB color.
|
||||
*
|
||||
* For this example, we'll assume that this data structure matches the way
|
||||
* our application has stored the image in memory, so we can just pass a
|
||||
* pointer to our image buffer. In particular, let's say that the image is
|
||||
* RGB color and is described by:
|
||||
*/
|
||||
|
||||
extern JSAMPLE * image_buffer; /* Points to large array of R,G,B-order data */
|
||||
extern int image_height; /* Number of rows in image */
|
||||
extern int image_width; /* Number of columns in image */
|
||||
|
||||
|
||||
/*
|
||||
* Sample routine for JPEG compression. We assume that the target file name
|
||||
* and a compression quality factor are passed in.
|
||||
*/
|
||||
|
||||
GLOBAL(void)
|
||||
write_JPEG_file (char * filename, int quality)
|
||||
{
|
||||
/* This struct contains the JPEG compression parameters and pointers to
|
||||
* working space (which is allocated as needed by the JPEG library).
|
||||
* It is possible to have several such structures, representing multiple
|
||||
* compression/decompression processes, in existence at once. We refer
|
||||
* to any one struct (and its associated working data) as a "JPEG object".
|
||||
*/
|
||||
struct jpeg_compress_struct cinfo;
|
||||
/* This struct represents a JPEG error handler. It is declared separately
|
||||
* because applications often want to supply a specialized error handler
|
||||
* (see the second half of this file for an example). But here we just
|
||||
* take the easy way out and use the standard error handler, which will
|
||||
* print a message on stderr and call exit() if compression fails.
|
||||
* Note that this struct must live as long as the main JPEG parameter
|
||||
* struct, to avoid dangling-pointer problems.
|
||||
*/
|
||||
struct jpeg_error_mgr jerr;
|
||||
/* More stuff */
|
||||
FILE * outfile; /* target file */
|
||||
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
|
||||
int row_stride; /* physical row width in image buffer */
|
||||
|
||||
/* Step 1: allocate and initialize JPEG compression object */
|
||||
|
||||
/* We have to set up the error handler first, in case the initialization
|
||||
* step fails. (Unlikely, but it could happen if you are out of memory.)
|
||||
* This routine fills in the contents of struct jerr, and returns jerr's
|
||||
* address which we place into the link field in cinfo.
|
||||
*/
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
/* Now we can initialize the JPEG compression object. */
|
||||
jpeg_create_compress(&cinfo);
|
||||
|
||||
/* Step 2: specify data destination (eg, a file) */
|
||||
/* Note: steps 2 and 3 can be done in either order. */
|
||||
|
||||
/* Here we use the library-supplied code to send compressed data to a
|
||||
* stdio stream. You can also write your own code to do something else.
|
||||
* VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
|
||||
* requires it in order to write binary files.
|
||||
*/
|
||||
if ((outfile = fopen(filename, "wb")) == NULL) {
|
||||
fprintf(stderr, "can't open %s\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
jpeg_stdio_dest(&cinfo, outfile);
|
||||
|
||||
/* Step 3: set parameters for compression */
|
||||
|
||||
/* First we supply a description of the input image.
|
||||
* Four fields of the cinfo struct must be filled in:
|
||||
*/
|
||||
cinfo.image_width = image_width; /* image width and height, in pixels */
|
||||
cinfo.image_height = image_height;
|
||||
cinfo.input_components = 3; /* # of color components per pixel */
|
||||
cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
|
||||
/* Now use the library's routine to set default compression parameters.
|
||||
* (You must set at least cinfo.in_color_space before calling this,
|
||||
* since the defaults depend on the source color space.)
|
||||
*/
|
||||
jpeg_set_defaults(&cinfo);
|
||||
/* Now you can set any non-default parameters you wish to.
|
||||
* Here we just illustrate the use of quality (quantization table) scaling:
|
||||
*/
|
||||
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
|
||||
|
||||
/* Step 4: Start compressor */
|
||||
|
||||
/* TRUE ensures that we will write a complete interchange-JPEG file.
|
||||
* Pass TRUE unless you are very sure of what you're doing.
|
||||
*/
|
||||
jpeg_start_compress(&cinfo, TRUE);
|
||||
|
||||
/* Step 5: while (scan lines remain to be written) */
|
||||
/* jpeg_write_scanlines(...); */
|
||||
|
||||
/* Here we use the library's state variable cinfo.next_scanline as the
|
||||
* loop counter, so that we don't have to keep track ourselves.
|
||||
* To keep things simple, we pass one scanline per call; you can pass
|
||||
* more if you wish, though.
|
||||
*/
|
||||
row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */
|
||||
|
||||
while (cinfo.next_scanline < cinfo.image_height) {
|
||||
/* jpeg_write_scanlines expects an array of pointers to scanlines.
|
||||
* Here the array is only one element long, but you could pass
|
||||
* more than one scanline at a time if that's more convenient.
|
||||
*/
|
||||
row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
|
||||
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
|
||||
}
|
||||
|
||||
/* Step 6: Finish compression */
|
||||
|
||||
jpeg_finish_compress(&cinfo);
|
||||
/* After finish_compress, we can close the output file. */
|
||||
fclose(outfile);
|
||||
|
||||
/* Step 7: release JPEG compression object */
|
||||
|
||||
/* This is an important step since it will release a good deal of memory. */
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
|
||||
/* And we're done! */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SOME FINE POINTS:
|
||||
*
|
||||
* In the above loop, we ignored the return value of jpeg_write_scanlines,
|
||||
* which is the number of scanlines actually written. We could get away
|
||||
* with this because we were only relying on the value of cinfo.next_scanline,
|
||||
* which will be incremented correctly. If you maintain additional loop
|
||||
* variables then you should be careful to increment them properly.
|
||||
* Actually, for output to a stdio stream you needn't worry, because
|
||||
* then jpeg_write_scanlines will write all the lines passed (or else exit
|
||||
* with a fatal error). Partial writes can only occur if you use a data
|
||||
* destination module that can demand suspension of the compressor.
|
||||
* (If you don't know what that's for, you don't need it.)
|
||||
*
|
||||
* If the compressor requires full-image buffers (for entropy-coding
|
||||
* optimization or a multi-scan JPEG file), it will create temporary
|
||||
* files for anything that doesn't fit within the maximum-memory setting.
|
||||
* (Note that temp files are NOT needed if you use the default parameters.)
|
||||
* On some systems you may need to set up a signal handler to ensure that
|
||||
* temporary files are deleted if the program is interrupted. See libjpeg.txt.
|
||||
*
|
||||
* Scanlines MUST be supplied in top-to-bottom order if you want your JPEG
|
||||
* files to be compatible with everyone else's. If you cannot readily read
|
||||
* your data in that order, you'll need an intermediate array to hold the
|
||||
* image. See rdtarga.c or rdbmp.c for examples of handling bottom-to-top
|
||||
* source data using the JPEG code's internal virtual-array mechanisms.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/******************** JPEG DECOMPRESSION SAMPLE INTERFACE *******************/
|
||||
|
||||
/* This half of the example shows how to read data from the JPEG decompressor.
|
||||
* It's a bit more refined than the above, in that we show:
|
||||
* (a) how to modify the JPEG library's standard error-reporting behavior;
|
||||
* (b) how to allocate workspace using the library's memory manager.
|
||||
*
|
||||
* Just to make this example a little different from the first one, we'll
|
||||
* assume that we do not intend to put the whole image into an in-memory
|
||||
* buffer, but to send it line-by-line someplace else. We need a one-
|
||||
* scanline-high JSAMPLE array as a work buffer, and we will let the JPEG
|
||||
* memory manager allocate it for us. This approach is actually quite useful
|
||||
* because we don't need to remember to deallocate the buffer separately: it
|
||||
* will go away automatically when the JPEG object is cleaned up.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* ERROR HANDLING:
|
||||
*
|
||||
* The JPEG library's standard error handler (jerror.c) is divided into
|
||||
* several "methods" which you can override individually. This lets you
|
||||
* adjust the behavior without duplicating a lot of code, which you might
|
||||
* have to update with each future release.
|
||||
*
|
||||
* Our example here shows how to override the "error_exit" method so that
|
||||
* control is returned to the library's caller when a fatal error occurs,
|
||||
* rather than calling exit() as the standard error_exit method does.
|
||||
*
|
||||
* We use C's setjmp/longjmp facility to return control. This means that the
|
||||
* routine which calls the JPEG library must first execute a setjmp() call to
|
||||
* establish the return point. We want the replacement error_exit to do a
|
||||
* longjmp(). But we need to make the setjmp buffer accessible to the
|
||||
* error_exit routine. To do this, we make a private extension of the
|
||||
* standard JPEG error handler object. (If we were using C++, we'd say we
|
||||
* were making a subclass of the regular error handler.)
|
||||
*
|
||||
* Here's the extended error handler struct:
|
||||
*/
|
||||
|
||||
struct my_error_mgr {
|
||||
struct jpeg_error_mgr pub; /* "public" fields */
|
||||
|
||||
jmp_buf setjmp_buffer; /* for return to caller */
|
||||
};
|
||||
|
||||
typedef struct my_error_mgr * my_error_ptr;
|
||||
|
||||
/*
|
||||
* Here's the routine that will replace the standard error_exit method:
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
my_error_exit (j_common_ptr cinfo)
|
||||
{
|
||||
/* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
|
||||
my_error_ptr myerr = (my_error_ptr) cinfo->err;
|
||||
|
||||
/* Always display the message. */
|
||||
/* We could postpone this until after returning, if we chose. */
|
||||
(*cinfo->err->output_message) (cinfo);
|
||||
|
||||
/* Return control to the setjmp point */
|
||||
longjmp(myerr->setjmp_buffer, 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sample routine for JPEG decompression. We assume that the source file name
|
||||
* is passed in. We want to return 1 on success, 0 on error.
|
||||
*/
|
||||
|
||||
|
||||
GLOBAL(int)
|
||||
read_JPEG_file (char * filename)
|
||||
{
|
||||
/* This struct contains the JPEG decompression parameters and pointers to
|
||||
* working space (which is allocated as needed by the JPEG library).
|
||||
*/
|
||||
struct jpeg_decompress_struct cinfo;
|
||||
/* We use our private extension JPEG error handler.
|
||||
* Note that this struct must live as long as the main JPEG parameter
|
||||
* struct, to avoid dangling-pointer problems.
|
||||
*/
|
||||
struct my_error_mgr jerr;
|
||||
/* More stuff */
|
||||
FILE * infile; /* source file */
|
||||
JSAMPARRAY buffer; /* Output row buffer */
|
||||
int row_stride; /* physical row width in output buffer */
|
||||
|
||||
/* In this example we want to open the input file before doing anything else,
|
||||
* so that the setjmp() error recovery below can assume the file is open.
|
||||
* VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
|
||||
* requires it in order to read binary files.
|
||||
*/
|
||||
|
||||
if ((infile = fopen(filename, "rb")) == NULL) {
|
||||
fprintf(stderr, "can't open %s\n", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Step 1: allocate and initialize JPEG decompression object */
|
||||
|
||||
/* We set up the normal JPEG error routines, then override error_exit. */
|
||||
cinfo.err = jpeg_std_error(&jerr.pub);
|
||||
jerr.pub.error_exit = my_error_exit;
|
||||
/* Establish the setjmp return context for my_error_exit to use. */
|
||||
if (setjmp(jerr.setjmp_buffer)) {
|
||||
/* If we get here, the JPEG code has signaled an error.
|
||||
* We need to clean up the JPEG object, close the input file, and return.
|
||||
*/
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
fclose(infile);
|
||||
return 0;
|
||||
}
|
||||
/* Now we can initialize the JPEG decompression object. */
|
||||
jpeg_create_decompress(&cinfo);
|
||||
|
||||
/* Step 2: specify data source (eg, a file) */
|
||||
|
||||
jpeg_stdio_src(&cinfo, infile);
|
||||
|
||||
/* Step 3: read file parameters with jpeg_read_header() */
|
||||
|
||||
(void) jpeg_read_header(&cinfo, TRUE);
|
||||
/* We can ignore the return value from jpeg_read_header since
|
||||
* (a) suspension is not possible with the stdio data source, and
|
||||
* (b) we passed TRUE to reject a tables-only JPEG file as an error.
|
||||
* See libjpeg.txt for more info.
|
||||
*/
|
||||
|
||||
/* Step 4: set parameters for decompression */
|
||||
|
||||
/* In this example, we don't need to change any of the defaults set by
|
||||
* jpeg_read_header(), so we do nothing here.
|
||||
*/
|
||||
|
||||
/* Step 5: Start decompressor */
|
||||
|
||||
(void) jpeg_start_decompress(&cinfo);
|
||||
/* We can ignore the return value since suspension is not possible
|
||||
* with the stdio data source.
|
||||
*/
|
||||
|
||||
/* We may need to do some setup of our own at this point before reading
|
||||
* the data. After jpeg_start_decompress() we have the correct scaled
|
||||
* output image dimensions available, as well as the output colormap
|
||||
* if we asked for color quantization.
|
||||
* In this example, we need to make an output work buffer of the right size.
|
||||
*/
|
||||
/* JSAMPLEs per row in output buffer */
|
||||
row_stride = cinfo.output_width * cinfo.output_components;
|
||||
/* Make a one-row-high sample array that will go away when done with image */
|
||||
buffer = (*cinfo.mem->alloc_sarray)
|
||||
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
|
||||
|
||||
/* Step 6: while (scan lines remain to be read) */
|
||||
/* jpeg_read_scanlines(...); */
|
||||
|
||||
/* Here we use the library's state variable cinfo.output_scanline as the
|
||||
* loop counter, so that we don't have to keep track ourselves.
|
||||
*/
|
||||
while (cinfo.output_scanline < cinfo.output_height) {
|
||||
/* jpeg_read_scanlines expects an array of pointers to scanlines.
|
||||
* Here the array is only one element long, but you could ask for
|
||||
* more than one scanline at a time if that's more convenient.
|
||||
*/
|
||||
(void) jpeg_read_scanlines(&cinfo, buffer, 1);
|
||||
/* Assume put_scanline_someplace wants a pointer and sample count. */
|
||||
put_scanline_someplace(buffer[0], row_stride);
|
||||
}
|
||||
|
||||
/* Step 7: Finish decompression */
|
||||
|
||||
(void) jpeg_finish_decompress(&cinfo);
|
||||
/* We can ignore the return value since suspension is not possible
|
||||
* with the stdio data source.
|
||||
*/
|
||||
|
||||
/* Step 8: Release JPEG decompression object */
|
||||
|
||||
/* This is an important step since it will release a good deal of memory. */
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
|
||||
/* After finish_decompress, we can close the input file.
|
||||
* Here we postpone it until after no more JPEG errors are possible,
|
||||
* so as to simplify the setjmp error logic above. (Actually, I don't
|
||||
* think that jpeg_destroy can do an error exit, but why assume anything...)
|
||||
*/
|
||||
fclose(infile);
|
||||
|
||||
/* At this point you may want to check to see whether any corrupt-data
|
||||
* warnings occurred (test whether jerr.pub.num_warnings is nonzero).
|
||||
*/
|
||||
|
||||
/* And we're done! */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SOME FINE POINTS:
|
||||
*
|
||||
* In the above code, we ignored the return value of jpeg_read_scanlines,
|
||||
* which is the number of scanlines actually read. We could get away with
|
||||
* this because we asked for only one line at a time and we weren't using
|
||||
* a suspending data source. See libjpeg.txt for more info.
|
||||
*
|
||||
* We cheated a bit by calling alloc_sarray() after jpeg_start_decompress();
|
||||
* we should have done it beforehand to ensure that the space would be
|
||||
* counted against the JPEG max_memory setting. In some systems the above
|
||||
* code would risk an out-of-memory error. However, in general we don't
|
||||
* know the output image dimensions before jpeg_start_decompress(), unless we
|
||||
* call jpeg_calc_output_dimensions(). See libjpeg.txt for more about this.
|
||||
*
|
||||
* Scanlines are returned in the same order as they appear in the JPEG file,
|
||||
* which is standardly top-to-bottom. If you must emit data bottom-to-top,
|
||||
* you can use one of the virtual arrays provided by the JPEG memory manager
|
||||
* to invert the data. See wrbmp.c for an example.
|
||||
*
|
||||
* As with compression, some operating modes may require temporary files.
|
||||
* On some systems you may need to set up a signal handler to ensure that
|
||||
* temporary files are deleted if the program is interrupted. See libjpeg.txt.
|
||||
*/
|
||||
|
|
@ -1,167 +0,0 @@
|
|||
/*
|
||||
* jmemansi.c
|
||||
*
|
||||
* Copyright (C) 1992-1996, 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 provides a simple generic implementation of the system-
|
||||
* dependent portion of the JPEG memory manager. This implementation
|
||||
* assumes that you have the ANSI-standard library routine tmpfile().
|
||||
* Also, the problem of determining the amount of memory available
|
||||
* is shoved onto the user.
|
||||
*/
|
||||
|
||||
#define JPEG_INTERNALS
|
||||
#include "jinclude.h"
|
||||
#include "jpeglib.h"
|
||||
#include "jmemsys.h" /* import the system-dependent declarations */
|
||||
|
||||
#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */
|
||||
extern void * malloc JPP((size_t size));
|
||||
extern void free JPP((void *ptr));
|
||||
#endif
|
||||
|
||||
#ifndef SEEK_SET /* pre-ANSI systems may not define this; */
|
||||
#define SEEK_SET 0 /* if not, assume 0 is correct */
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Memory allocation and freeing are controlled by the regular library
|
||||
* routines malloc() and free().
|
||||
*/
|
||||
|
||||
GLOBAL(void *)
|
||||
jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
|
||||
{
|
||||
return (void *) malloc(sizeofobject);
|
||||
}
|
||||
|
||||
GLOBAL(void)
|
||||
jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
|
||||
{
|
||||
free(object);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* "Large" objects are treated the same as "small" ones.
|
||||
* NB: although we include FAR keywords in the routine declarations,
|
||||
* this file won't actually work in 80x86 small/medium model; at least,
|
||||
* you probably won't be able to process useful-size images in only 64KB.
|
||||
*/
|
||||
|
||||
GLOBAL(void FAR *)
|
||||
jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
|
||||
{
|
||||
return (void FAR *) malloc(sizeofobject);
|
||||
}
|
||||
|
||||
GLOBAL(void)
|
||||
jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
|
||||
{
|
||||
free(object);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This routine computes the total memory space available for allocation.
|
||||
* It's impossible to do this in a portable way; our current solution is
|
||||
* to make the user tell us (with a default value set at compile time).
|
||||
* If you can actually get the available space, it's a good idea to subtract
|
||||
* a slop factor of 5% or so.
|
||||
*/
|
||||
|
||||
#ifndef DEFAULT_MAX_MEM /* so can override from makefile */
|
||||
#define DEFAULT_MAX_MEM 1000000L /* default: one megabyte */
|
||||
#endif
|
||||
|
||||
GLOBAL(long)
|
||||
jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
|
||||
long max_bytes_needed, long already_allocated)
|
||||
{
|
||||
return cinfo->mem->max_memory_to_use - already_allocated;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Backing store (temporary file) management.
|
||||
* Backing store objects are only used when the value returned by
|
||||
* jpeg_mem_available is less than the total space needed. You can dispense
|
||||
* with these routines if you have plenty of virtual memory; see jmemnobs.c.
|
||||
*/
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
read_backing_store (j_common_ptr cinfo, backing_store_ptr info,
|
||||
void FAR * buffer_address,
|
||||
long file_offset, long byte_count)
|
||||
{
|
||||
if (fseek(info->temp_file, file_offset, SEEK_SET))
|
||||
ERREXIT(cinfo, JERR_TFILE_SEEK);
|
||||
if (JFREAD(info->temp_file, buffer_address, byte_count)
|
||||
!= (size_t) byte_count)
|
||||
ERREXIT(cinfo, JERR_TFILE_READ);
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
write_backing_store (j_common_ptr cinfo, backing_store_ptr info,
|
||||
void FAR * buffer_address,
|
||||
long file_offset, long byte_count)
|
||||
{
|
||||
if (fseek(info->temp_file, file_offset, SEEK_SET))
|
||||
ERREXIT(cinfo, JERR_TFILE_SEEK);
|
||||
if (JFWRITE(info->temp_file, buffer_address, byte_count)
|
||||
!= (size_t) byte_count)
|
||||
ERREXIT(cinfo, JERR_TFILE_WRITE);
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
close_backing_store (j_common_ptr cinfo, backing_store_ptr info)
|
||||
{
|
||||
fclose(info->temp_file);
|
||||
/* Since this implementation uses tmpfile() to create the file,
|
||||
* no explicit file deletion is needed.
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initial opening of a backing-store object.
|
||||
*
|
||||
* This version uses tmpfile(), which constructs a suitable file name
|
||||
* behind the scenes. We don't have to use info->temp_name[] at all;
|
||||
* indeed, we can't even find out the actual name of the temp file.
|
||||
*/
|
||||
|
||||
GLOBAL(void)
|
||||
jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
|
||||
long total_bytes_needed)
|
||||
{
|
||||
if ((info->temp_file = tmpfile()) == NULL)
|
||||
ERREXITS(cinfo, JERR_TFILE_CREATE, "");
|
||||
info->read_backing_store = read_backing_store;
|
||||
info->write_backing_store = write_backing_store;
|
||||
info->close_backing_store = close_backing_store;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* These routines take care of any system-dependent initialization and
|
||||
* cleanup required.
|
||||
*/
|
||||
|
||||
GLOBAL(long)
|
||||
jpeg_mem_init (j_common_ptr cinfo)
|
||||
{
|
||||
return DEFAULT_MAX_MEM; /* default for max_memory_to_use */
|
||||
}
|
||||
|
||||
GLOBAL(void)
|
||||
jpeg_mem_term (j_common_ptr cinfo)
|
||||
{
|
||||
/* no work */
|
||||
}
|
||||
|
|
@ -1,638 +0,0 @@
|
|||
/*
|
||||
* jmemdos.c
|
||||
*
|
||||
* Copyright (C) 1992-1997, 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 provides an MS-DOS-compatible implementation of the system-
|
||||
* dependent portion of the JPEG memory manager. Temporary data can be
|
||||
* stored in extended or expanded memory as well as in regular DOS files.
|
||||
*
|
||||
* If you use this file, you must be sure that NEED_FAR_POINTERS is defined
|
||||
* if you compile in a small-data memory model; it should NOT be defined if
|
||||
* you use a large-data memory model. This file is not recommended if you
|
||||
* are using a flat-memory-space 386 environment such as DJGCC or Watcom C.
|
||||
* Also, this code will NOT work if struct fields are aligned on greater than
|
||||
* 2-byte boundaries.
|
||||
*
|
||||
* Based on code contributed by Ge' Weijers.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If you have both extended and expanded memory, you may want to change the
|
||||
* order in which they are tried in jopen_backing_store. On a 286 machine
|
||||
* expanded memory is usually faster, since extended memory access involves
|
||||
* an expensive protected-mode-and-back switch. On 386 and better, extended
|
||||
* memory is usually faster. As distributed, the code tries extended memory
|
||||
* first (what? not everyone has a 386? :-).
|
||||
*
|
||||
* You can disable use of extended/expanded memory entirely by altering these
|
||||
* definitions or overriding them from the Makefile (eg, -DEMS_SUPPORTED=0).
|
||||
*/
|
||||
|
||||
#ifndef XMS_SUPPORTED
|
||||
#define XMS_SUPPORTED 1
|
||||
#endif
|
||||
#ifndef EMS_SUPPORTED
|
||||
#define EMS_SUPPORTED 1
|
||||
#endif
|
||||
|
||||
|
||||
#define JPEG_INTERNALS
|
||||
#include "jinclude.h"
|
||||
#include "jpeglib.h"
|
||||
#include "jmemsys.h" /* import the system-dependent declarations */
|
||||
|
||||
#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare these */
|
||||
extern void * malloc JPP((size_t size));
|
||||
extern void free JPP((void *ptr));
|
||||
extern char * getenv JPP((const char * name));
|
||||
#endif
|
||||
|
||||
#ifdef NEED_FAR_POINTERS
|
||||
|
||||
#ifdef __TURBOC__
|
||||
/* These definitions work for Borland C (Turbo C) */
|
||||
#include <alloc.h> /* need farmalloc(), farfree() */
|
||||
#define far_malloc(x) farmalloc(x)
|
||||
#define far_free(x) farfree(x)
|
||||
#else
|
||||
/* These definitions work for Microsoft C and compatible compilers */
|
||||
#include <malloc.h> /* need _fmalloc(), _ffree() */
|
||||
#define far_malloc(x) _fmalloc(x)
|
||||
#define far_free(x) _ffree(x)
|
||||
#endif
|
||||
|
||||
#else /* not NEED_FAR_POINTERS */
|
||||
|
||||
#define far_malloc(x) malloc(x)
|
||||
#define far_free(x) free(x)
|
||||
|
||||
#endif /* NEED_FAR_POINTERS */
|
||||
|
||||
#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */
|
||||
#define READ_BINARY "r"
|
||||
#else
|
||||
#define READ_BINARY "rb"
|
||||
#endif
|
||||
|
||||
#ifndef USE_MSDOS_MEMMGR /* make sure user got configuration right */
|
||||
You forgot to define USE_MSDOS_MEMMGR in jconfig.h. /* deliberate syntax error */
|
||||
#endif
|
||||
|
||||
#if MAX_ALLOC_CHUNK >= 65535L /* make sure jconfig.h got this right */
|
||||
MAX_ALLOC_CHUNK should be less than 64K. /* deliberate syntax error */
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Declarations for assembly-language support routines (see jmemdosa.asm).
|
||||
*
|
||||
* The functions are declared "far" as are all their pointer arguments;
|
||||
* this ensures the assembly source code will work regardless of the
|
||||
* compiler memory model. We assume "short" is 16 bits, "long" is 32.
|
||||
*/
|
||||
|
||||
typedef void far * XMSDRIVER; /* actually a pointer to code */
|
||||
typedef struct { /* registers for calling XMS driver */
|
||||
unsigned short ax, dx, bx;
|
||||
void far * ds_si;
|
||||
} XMScontext;
|
||||
typedef struct { /* registers for calling EMS driver */
|
||||
unsigned short ax, dx, bx;
|
||||
void far * ds_si;
|
||||
} EMScontext;
|
||||
|
||||
extern short far jdos_open JPP((short far * handle, char far * filename));
|
||||
extern short far jdos_close JPP((short handle));
|
||||
extern short far jdos_seek JPP((short handle, long offset));
|
||||
extern short far jdos_read JPP((short handle, void far * buffer,
|
||||
unsigned short count));
|
||||
extern short far jdos_write JPP((short handle, void far * buffer,
|
||||
unsigned short count));
|
||||
extern void far jxms_getdriver JPP((XMSDRIVER far *));
|
||||
extern void far jxms_calldriver JPP((XMSDRIVER, XMScontext far *));
|
||||
extern short far jems_available JPP((void));
|
||||
extern void far jems_calldriver JPP((EMScontext far *));
|
||||
|
||||
|
||||
/*
|
||||
* Selection of a file name for a temporary file.
|
||||
* This is highly system-dependent, and you may want to customize it.
|
||||
*/
|
||||
|
||||
static int next_file_num; /* to distinguish among several temp files */
|
||||
|
||||
LOCAL(void)
|
||||
select_file_name (char * fname)
|
||||
{
|
||||
const char * env;
|
||||
char * ptr;
|
||||
FILE * tfile;
|
||||
|
||||
/* Keep generating file names till we find one that's not in use */
|
||||
for (;;) {
|
||||
/* Get temp directory name from environment TMP or TEMP variable;
|
||||
* if none, use "."
|
||||
*/
|
||||
if ((env = (const char *) getenv("TMP")) == NULL)
|
||||
if ((env = (const char *) getenv("TEMP")) == NULL)
|
||||
env = ".";
|
||||
if (*env == '\0') /* null string means "." */
|
||||
env = ".";
|
||||
ptr = fname; /* copy name to fname */
|
||||
while (*env != '\0')
|
||||
*ptr++ = *env++;
|
||||
if (ptr[-1] != '\\' && ptr[-1] != '/')
|
||||
*ptr++ = '\\'; /* append backslash if not in env variable */
|
||||
/* Append a suitable file name */
|
||||
next_file_num++; /* advance counter */
|
||||
sprintf(ptr, "JPG%03d.TMP", next_file_num);
|
||||
/* Probe to see if file name is already in use */
|
||||
if ((tfile = fopen(fname, READ_BINARY)) == NULL)
|
||||
break;
|
||||
fclose(tfile); /* oops, it's there; close tfile & try again */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Near-memory allocation and freeing are controlled by the regular library
|
||||
* routines malloc() and free().
|
||||
*/
|
||||
|
||||
GLOBAL(void *)
|
||||
jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
|
||||
{
|
||||
return (void *) malloc(sizeofobject);
|
||||
}
|
||||
|
||||
GLOBAL(void)
|
||||
jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
|
||||
{
|
||||
free(object);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* "Large" objects are allocated in far memory, if possible
|
||||
*/
|
||||
|
||||
GLOBAL(void FAR *)
|
||||
jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
|
||||
{
|
||||
return (void FAR *) far_malloc(sizeofobject);
|
||||
}
|
||||
|
||||
GLOBAL(void)
|
||||
jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
|
||||
{
|
||||
far_free(object);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This routine computes the total memory space available for allocation.
|
||||
* It's impossible to do this in a portable way; our current solution is
|
||||
* to make the user tell us (with a default value set at compile time).
|
||||
* If you can actually get the available space, it's a good idea to subtract
|
||||
* a slop factor of 5% or so.
|
||||
*/
|
||||
|
||||
#ifndef DEFAULT_MAX_MEM /* so can override from makefile */
|
||||
#define DEFAULT_MAX_MEM 300000L /* for total usage about 450K */
|
||||
#endif
|
||||
|
||||
GLOBAL(long)
|
||||
jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
|
||||
long max_bytes_needed, long already_allocated)
|
||||
{
|
||||
return cinfo->mem->max_memory_to_use - already_allocated;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Backing store (temporary file) management.
|
||||
* Backing store objects are only used when the value returned by
|
||||
* jpeg_mem_available is less than the total space needed. You can dispense
|
||||
* with these routines if you have plenty of virtual memory; see jmemnobs.c.
|
||||
*/
|
||||
|
||||
/*
|
||||
* For MS-DOS we support three types of backing storage:
|
||||
* 1. Conventional DOS files. We access these by direct DOS calls rather
|
||||
* than via the stdio package. This provides a bit better performance,
|
||||
* but the real reason is that the buffers to be read or written are FAR.
|
||||
* The stdio library for small-data memory models can't cope with that.
|
||||
* 2. Extended memory, accessed per the XMS V2.0 specification.
|
||||
* 3. Expanded memory, accessed per the LIM/EMS 4.0 specification.
|
||||
* You'll need copies of those specs to make sense of the related code.
|
||||
* The specs are available by Internet FTP from the SIMTEL archives
|
||||
* (oak.oakland.edu and its various mirror sites). See files
|
||||
* pub/msdos/microsoft/xms20.arc and pub/msdos/info/limems41.zip.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Access methods for a DOS file.
|
||||
*/
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
read_file_store (j_common_ptr cinfo, backing_store_ptr info,
|
||||
void FAR * buffer_address,
|
||||
long file_offset, long byte_count)
|
||||
{
|
||||
if (jdos_seek(info->handle.file_handle, file_offset))
|
||||
ERREXIT(cinfo, JERR_TFILE_SEEK);
|
||||
/* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
|
||||
if (byte_count > 65535L) /* safety check */
|
||||
ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
|
||||
if (jdos_read(info->handle.file_handle, buffer_address,
|
||||
(unsigned short) byte_count))
|
||||
ERREXIT(cinfo, JERR_TFILE_READ);
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
write_file_store (j_common_ptr cinfo, backing_store_ptr info,
|
||||
void FAR * buffer_address,
|
||||
long file_offset, long byte_count)
|
||||
{
|
||||
if (jdos_seek(info->handle.file_handle, file_offset))
|
||||
ERREXIT(cinfo, JERR_TFILE_SEEK);
|
||||
/* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
|
||||
if (byte_count > 65535L) /* safety check */
|
||||
ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
|
||||
if (jdos_write(info->handle.file_handle, buffer_address,
|
||||
(unsigned short) byte_count))
|
||||
ERREXIT(cinfo, JERR_TFILE_WRITE);
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
close_file_store (j_common_ptr cinfo, backing_store_ptr info)
|
||||
{
|
||||
jdos_close(info->handle.file_handle); /* close the file */
|
||||
remove(info->temp_name); /* delete the file */
|
||||
/* If your system doesn't have remove(), try unlink() instead.
|
||||
* remove() is the ANSI-standard name for this function, but
|
||||
* unlink() was more common in pre-ANSI systems.
|
||||
*/
|
||||
TRACEMSS(cinfo, 1, JTRC_TFILE_CLOSE, info->temp_name);
|
||||
}
|
||||
|
||||
|
||||
LOCAL(boolean)
|
||||
open_file_store (j_common_ptr cinfo, backing_store_ptr info,
|
||||
long total_bytes_needed)
|
||||
{
|
||||
short handle;
|
||||
|
||||
select_file_name(info->temp_name);
|
||||
if (jdos_open((short far *) & handle, (char far *) info->temp_name)) {
|
||||
/* might as well exit since jpeg_open_backing_store will fail anyway */
|
||||
ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
|
||||
return FALSE;
|
||||
}
|
||||
info->handle.file_handle = handle;
|
||||
info->read_backing_store = read_file_store;
|
||||
info->write_backing_store = write_file_store;
|
||||
info->close_backing_store = close_file_store;
|
||||
TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name);
|
||||
return TRUE; /* succeeded */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Access methods for extended memory.
|
||||
*/
|
||||
|
||||
#if XMS_SUPPORTED
|
||||
|
||||
static XMSDRIVER xms_driver; /* saved address of XMS driver */
|
||||
|
||||
typedef union { /* either long offset or real-mode pointer */
|
||||
long offset;
|
||||
void far * ptr;
|
||||
} XMSPTR;
|
||||
|
||||
typedef struct { /* XMS move specification structure */
|
||||
long length;
|
||||
XMSH src_handle;
|
||||
XMSPTR src;
|
||||
XMSH dst_handle;
|
||||
XMSPTR dst;
|
||||
} XMSspec;
|
||||
|
||||
#define ODD(X) (((X) & 1L) != 0)
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
read_xms_store (j_common_ptr cinfo, backing_store_ptr info,
|
||||
void FAR * buffer_address,
|
||||
long file_offset, long byte_count)
|
||||
{
|
||||
XMScontext ctx;
|
||||
XMSspec spec;
|
||||
char endbuffer[2];
|
||||
|
||||
/* The XMS driver can't cope with an odd length, so handle the last byte
|
||||
* specially if byte_count is odd. We don't expect this to be common.
|
||||
*/
|
||||
|
||||
spec.length = byte_count & (~ 1L);
|
||||
spec.src_handle = info->handle.xms_handle;
|
||||
spec.src.offset = file_offset;
|
||||
spec.dst_handle = 0;
|
||||
spec.dst.ptr = buffer_address;
|
||||
|
||||
ctx.ds_si = (void far *) & spec;
|
||||
ctx.ax = 0x0b00; /* EMB move */
|
||||
jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
|
||||
if (ctx.ax != 1)
|
||||
ERREXIT(cinfo, JERR_XMS_READ);
|
||||
|
||||
if (ODD(byte_count)) {
|
||||
read_xms_store(cinfo, info, (void FAR *) endbuffer,
|
||||
file_offset + byte_count - 1L, 2L);
|
||||
((char FAR *) buffer_address)[byte_count - 1L] = endbuffer[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
write_xms_store (j_common_ptr cinfo, backing_store_ptr info,
|
||||
void FAR * buffer_address,
|
||||
long file_offset, long byte_count)
|
||||
{
|
||||
XMScontext ctx;
|
||||
XMSspec spec;
|
||||
char endbuffer[2];
|
||||
|
||||
/* The XMS driver can't cope with an odd length, so handle the last byte
|
||||
* specially if byte_count is odd. We don't expect this to be common.
|
||||
*/
|
||||
|
||||
spec.length = byte_count & (~ 1L);
|
||||
spec.src_handle = 0;
|
||||
spec.src.ptr = buffer_address;
|
||||
spec.dst_handle = info->handle.xms_handle;
|
||||
spec.dst.offset = file_offset;
|
||||
|
||||
ctx.ds_si = (void far *) & spec;
|
||||
ctx.ax = 0x0b00; /* EMB move */
|
||||
jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
|
||||
if (ctx.ax != 1)
|
||||
ERREXIT(cinfo, JERR_XMS_WRITE);
|
||||
|
||||
if (ODD(byte_count)) {
|
||||
read_xms_store(cinfo, info, (void FAR *) endbuffer,
|
||||
file_offset + byte_count - 1L, 2L);
|
||||
endbuffer[0] = ((char FAR *) buffer_address)[byte_count - 1L];
|
||||
write_xms_store(cinfo, info, (void FAR *) endbuffer,
|
||||
file_offset + byte_count - 1L, 2L);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
close_xms_store (j_common_ptr cinfo, backing_store_ptr info)
|
||||
{
|
||||
XMScontext ctx;
|
||||
|
||||
ctx.dx = info->handle.xms_handle;
|
||||
ctx.ax = 0x0a00;
|
||||
jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
|
||||
TRACEMS1(cinfo, 1, JTRC_XMS_CLOSE, info->handle.xms_handle);
|
||||
/* we ignore any error return from the driver */
|
||||
}
|
||||
|
||||
|
||||
LOCAL(boolean)
|
||||
open_xms_store (j_common_ptr cinfo, backing_store_ptr info,
|
||||
long total_bytes_needed)
|
||||
{
|
||||
XMScontext ctx;
|
||||
|
||||
/* Get address of XMS driver */
|
||||
jxms_getdriver((XMSDRIVER far *) & xms_driver);
|
||||
if (xms_driver == NULL)
|
||||
return FALSE; /* no driver to be had */
|
||||
|
||||
/* Get version number, must be >= 2.00 */
|
||||
ctx.ax = 0x0000;
|
||||
jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
|
||||
if (ctx.ax < (unsigned short) 0x0200)
|
||||
return FALSE;
|
||||
|
||||
/* Try to get space (expressed in kilobytes) */
|
||||
ctx.dx = (unsigned short) ((total_bytes_needed + 1023L) >> 10);
|
||||
ctx.ax = 0x0900;
|
||||
jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
|
||||
if (ctx.ax != 1)
|
||||
return FALSE;
|
||||
|
||||
/* Succeeded, save the handle and away we go */
|
||||
info->handle.xms_handle = ctx.dx;
|
||||
info->read_backing_store = read_xms_store;
|
||||
info->write_backing_store = write_xms_store;
|
||||
info->close_backing_store = close_xms_store;
|
||||
TRACEMS1(cinfo, 1, JTRC_XMS_OPEN, ctx.dx);
|
||||
return TRUE; /* succeeded */
|
||||
}
|
||||
|
||||
#endif /* XMS_SUPPORTED */
|
||||
|
||||
|
||||
/*
|
||||
* Access methods for expanded memory.
|
||||
*/
|
||||
|
||||
#if EMS_SUPPORTED
|
||||
|
||||
/* The EMS move specification structure requires word and long fields aligned
|
||||
* at odd byte boundaries. Some compilers will align struct fields at even
|
||||
* byte boundaries. While it's usually possible to force byte alignment,
|
||||
* that causes an overall performance penalty and may pose problems in merging
|
||||
* JPEG into a larger application. Instead we accept some rather dirty code
|
||||
* here. Note this code would fail if the hardware did not allow odd-byte
|
||||
* word & long accesses, but all 80x86 CPUs do.
|
||||
*/
|
||||
|
||||
typedef void far * EMSPTR;
|
||||
|
||||
typedef union { /* EMS move specification structure */
|
||||
long length; /* It's easy to access first 4 bytes */
|
||||
char bytes[18]; /* Misaligned fields in here! */
|
||||
} EMSspec;
|
||||
|
||||
/* Macros for accessing misaligned fields */
|
||||
#define FIELD_AT(spec,offset,type) (*((type *) &(spec.bytes[offset])))
|
||||
#define SRC_TYPE(spec) FIELD_AT(spec,4,char)
|
||||
#define SRC_HANDLE(spec) FIELD_AT(spec,5,EMSH)
|
||||
#define SRC_OFFSET(spec) FIELD_AT(spec,7,unsigned short)
|
||||
#define SRC_PAGE(spec) FIELD_AT(spec,9,unsigned short)
|
||||
#define SRC_PTR(spec) FIELD_AT(spec,7,EMSPTR)
|
||||
#define DST_TYPE(spec) FIELD_AT(spec,11,char)
|
||||
#define DST_HANDLE(spec) FIELD_AT(spec,12,EMSH)
|
||||
#define DST_OFFSET(spec) FIELD_AT(spec,14,unsigned short)
|
||||
#define DST_PAGE(spec) FIELD_AT(spec,16,unsigned short)
|
||||
#define DST_PTR(spec) FIELD_AT(spec,14,EMSPTR)
|
||||
|
||||
#define EMSPAGESIZE 16384L /* gospel, see the EMS specs */
|
||||
|
||||
#define HIBYTE(W) (((W) >> 8) & 0xFF)
|
||||
#define LOBYTE(W) ((W) & 0xFF)
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
read_ems_store (j_common_ptr cinfo, backing_store_ptr info,
|
||||
void FAR * buffer_address,
|
||||
long file_offset, long byte_count)
|
||||
{
|
||||
EMScontext ctx;
|
||||
EMSspec spec;
|
||||
|
||||
spec.length = byte_count;
|
||||
SRC_TYPE(spec) = 1;
|
||||
SRC_HANDLE(spec) = info->handle.ems_handle;
|
||||
SRC_PAGE(spec) = (unsigned short) (file_offset / EMSPAGESIZE);
|
||||
SRC_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE);
|
||||
DST_TYPE(spec) = 0;
|
||||
DST_HANDLE(spec) = 0;
|
||||
DST_PTR(spec) = buffer_address;
|
||||
|
||||
ctx.ds_si = (void far *) & spec;
|
||||
ctx.ax = 0x5700; /* move memory region */
|
||||
jems_calldriver((EMScontext far *) & ctx);
|
||||
if (HIBYTE(ctx.ax) != 0)
|
||||
ERREXIT(cinfo, JERR_EMS_READ);
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
write_ems_store (j_common_ptr cinfo, backing_store_ptr info,
|
||||
void FAR * buffer_address,
|
||||
long file_offset, long byte_count)
|
||||
{
|
||||
EMScontext ctx;
|
||||
EMSspec spec;
|
||||
|
||||
spec.length = byte_count;
|
||||
SRC_TYPE(spec) = 0;
|
||||
SRC_HANDLE(spec) = 0;
|
||||
SRC_PTR(spec) = buffer_address;
|
||||
DST_TYPE(spec) = 1;
|
||||
DST_HANDLE(spec) = info->handle.ems_handle;
|
||||
DST_PAGE(spec) = (unsigned short) (file_offset / EMSPAGESIZE);
|
||||
DST_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE);
|
||||
|
||||
ctx.ds_si = (void far *) & spec;
|
||||
ctx.ax = 0x5700; /* move memory region */
|
||||
jems_calldriver((EMScontext far *) & ctx);
|
||||
if (HIBYTE(ctx.ax) != 0)
|
||||
ERREXIT(cinfo, JERR_EMS_WRITE);
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
close_ems_store (j_common_ptr cinfo, backing_store_ptr info)
|
||||
{
|
||||
EMScontext ctx;
|
||||
|
||||
ctx.ax = 0x4500;
|
||||
ctx.dx = info->handle.ems_handle;
|
||||
jems_calldriver((EMScontext far *) & ctx);
|
||||
TRACEMS1(cinfo, 1, JTRC_EMS_CLOSE, info->handle.ems_handle);
|
||||
/* we ignore any error return from the driver */
|
||||
}
|
||||
|
||||
|
||||
LOCAL(boolean)
|
||||
open_ems_store (j_common_ptr cinfo, backing_store_ptr info,
|
||||
long total_bytes_needed)
|
||||
{
|
||||
EMScontext ctx;
|
||||
|
||||
/* Is EMS driver there? */
|
||||
if (! jems_available())
|
||||
return FALSE;
|
||||
|
||||
/* Get status, make sure EMS is OK */
|
||||
ctx.ax = 0x4000;
|
||||
jems_calldriver((EMScontext far *) & ctx);
|
||||
if (HIBYTE(ctx.ax) != 0)
|
||||
return FALSE;
|
||||
|
||||
/* Get version, must be >= 4.0 */
|
||||
ctx.ax = 0x4600;
|
||||
jems_calldriver((EMScontext far *) & ctx);
|
||||
if (HIBYTE(ctx.ax) != 0 || LOBYTE(ctx.ax) < 0x40)
|
||||
return FALSE;
|
||||
|
||||
/* Try to allocate requested space */
|
||||
ctx.ax = 0x4300;
|
||||
ctx.bx = (unsigned short) ((total_bytes_needed + EMSPAGESIZE-1L) / EMSPAGESIZE);
|
||||
jems_calldriver((EMScontext far *) & ctx);
|
||||
if (HIBYTE(ctx.ax) != 0)
|
||||
return FALSE;
|
||||
|
||||
/* Succeeded, save the handle and away we go */
|
||||
info->handle.ems_handle = ctx.dx;
|
||||
info->read_backing_store = read_ems_store;
|
||||
info->write_backing_store = write_ems_store;
|
||||
info->close_backing_store = close_ems_store;
|
||||
TRACEMS1(cinfo, 1, JTRC_EMS_OPEN, ctx.dx);
|
||||
return TRUE; /* succeeded */
|
||||
}
|
||||
|
||||
#endif /* EMS_SUPPORTED */
|
||||
|
||||
|
||||
/*
|
||||
* Initial opening of a backing-store object.
|
||||
*/
|
||||
|
||||
GLOBAL(void)
|
||||
jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
|
||||
long total_bytes_needed)
|
||||
{
|
||||
/* Try extended memory, then expanded memory, then regular file. */
|
||||
#if XMS_SUPPORTED
|
||||
if (open_xms_store(cinfo, info, total_bytes_needed))
|
||||
return;
|
||||
#endif
|
||||
#if EMS_SUPPORTED
|
||||
if (open_ems_store(cinfo, info, total_bytes_needed))
|
||||
return;
|
||||
#endif
|
||||
if (open_file_store(cinfo, info, total_bytes_needed))
|
||||
return;
|
||||
ERREXITS(cinfo, JERR_TFILE_CREATE, "");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* These routines take care of any system-dependent initialization and
|
||||
* cleanup required.
|
||||
*/
|
||||
|
||||
GLOBAL(long)
|
||||
jpeg_mem_init (j_common_ptr cinfo)
|
||||
{
|
||||
next_file_num = 0; /* initialize temp file name generator */
|
||||
return DEFAULT_MAX_MEM; /* default for max_memory_to_use */
|
||||
}
|
||||
|
||||
GLOBAL(void)
|
||||
jpeg_mem_term (j_common_ptr cinfo)
|
||||
{
|
||||
/* Microsoft C, at least in v6.00A, will not successfully reclaim freed
|
||||
* blocks of size > 32Kbytes unless we give it a kick in the rear, like so:
|
||||
*/
|
||||
#ifdef NEED_FHEAPMIN
|
||||
_fheapmin();
|
||||
#endif
|
||||
}
|
||||
|
|
@ -1,289 +0,0 @@
|
|||
/*
|
||||
* jmemmac.c
|
||||
*
|
||||
* Copyright (C) 1992-1997, 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.
|
||||
*
|
||||
* jmemmac.c provides an Apple Macintosh implementation of the system-
|
||||
* dependent portion of the JPEG memory manager.
|
||||
*
|
||||
* If you use jmemmac.c, then you must define USE_MAC_MEMMGR in the
|
||||
* JPEG_INTERNALS part of jconfig.h.
|
||||
*
|
||||
* jmemmac.c uses the Macintosh toolbox routines NewPtr and DisposePtr
|
||||
* instead of malloc and free. It accurately determines the amount of
|
||||
* memory available by using CompactMem. Notice that if left to its
|
||||
* own devices, this code can chew up all available space in the
|
||||
* application's zone, with the exception of the rather small "slop"
|
||||
* factor computed in jpeg_mem_available(). The application can ensure
|
||||
* that more space is left over by reducing max_memory_to_use.
|
||||
*
|
||||
* Large images are swapped to disk using temporary files and System 7.0+'s
|
||||
* temporary folder functionality.
|
||||
*
|
||||
* Note that jmemmac.c depends on two features of MacOS that were first
|
||||
* introduced in System 7: FindFolder and the FSSpec-based calls.
|
||||
* If your application uses jmemmac.c and is run under System 6 or earlier,
|
||||
* and the jpeg library decides it needs a temporary file, it will abort,
|
||||
* printing error messages about requiring System 7. (If no temporary files
|
||||
* are created, it will run fine.)
|
||||
*
|
||||
* If you want to use jmemmac.c in an application that might be used with
|
||||
* System 6 or earlier, then you should remove dependencies on FindFolder
|
||||
* and the FSSpec calls. You will need to replace FindFolder with some
|
||||
* other mechanism for finding a place to put temporary files, and you
|
||||
* should replace the FSSpec calls with their HFS equivalents:
|
||||
*
|
||||
* FSpDelete -> HDelete
|
||||
* FSpGetFInfo -> HGetFInfo
|
||||
* FSpCreate -> HCreate
|
||||
* FSpOpenDF -> HOpen *** Note: not HOpenDF ***
|
||||
* FSMakeFSSpec -> (fill in spec by hand.)
|
||||
*
|
||||
* (Use HOpen instead of HOpenDF. HOpen is just a glue-interface to PBHOpen,
|
||||
* which is on all HFS macs. HOpenDF is a System 7 addition which avoids the
|
||||
* ages-old problem of names starting with a period.)
|
||||
*
|
||||
* Contributed by Sam Bushell (jsam@iagu.on.net) and
|
||||
* Dan Gildor (gyld@in-touch.com).
|
||||
*/
|
||||
|
||||
#define JPEG_INTERNALS
|
||||
#include "jinclude.h"
|
||||
#include "jpeglib.h"
|
||||
#include "jmemsys.h" /* import the system-dependent declarations */
|
||||
|
||||
#ifndef USE_MAC_MEMMGR /* make sure user got configuration right */
|
||||
You forgot to define USE_MAC_MEMMGR in jconfig.h. /* deliberate syntax error */
|
||||
#endif
|
||||
|
||||
#include <Memory.h> /* we use the MacOS memory manager */
|
||||
#include <Files.h> /* we use the MacOS File stuff */
|
||||
#include <Folders.h> /* we use the MacOS HFS stuff */
|
||||
#include <Script.h> /* for smSystemScript */
|
||||
#include <Gestalt.h> /* we use Gestalt to test for specific functionality */
|
||||
|
||||
#ifndef TEMP_FILE_NAME /* can override from jconfig.h or Makefile */
|
||||
#define TEMP_FILE_NAME "JPG%03d.TMP"
|
||||
#endif
|
||||
|
||||
static int next_file_num; /* to distinguish among several temp files */
|
||||
|
||||
|
||||
/*
|
||||
* Memory allocation and freeing are controlled by the MacOS library
|
||||
* routines NewPtr() and DisposePtr(), which allocate fixed-address
|
||||
* storage. Unfortunately, the IJG library isn't smart enough to cope
|
||||
* with relocatable storage.
|
||||
*/
|
||||
|
||||
GLOBAL(void *)
|
||||
jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
|
||||
{
|
||||
return (void *) NewPtr(sizeofobject);
|
||||
}
|
||||
|
||||
GLOBAL(void)
|
||||
jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
|
||||
{
|
||||
DisposePtr((Ptr) object);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* "Large" objects are treated the same as "small" ones.
|
||||
* NB: we include FAR keywords in the routine declarations simply for
|
||||
* consistency with the rest of the IJG code; FAR should expand to empty
|
||||
* on rational architectures like the Mac.
|
||||
*/
|
||||
|
||||
GLOBAL(void FAR *)
|
||||
jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
|
||||
{
|
||||
return (void FAR *) NewPtr(sizeofobject);
|
||||
}
|
||||
|
||||
GLOBAL(void)
|
||||
jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
|
||||
{
|
||||
DisposePtr((Ptr) object);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This routine computes the total memory space available for allocation.
|
||||
*/
|
||||
|
||||
GLOBAL(long)
|
||||
jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
|
||||
long max_bytes_needed, long already_allocated)
|
||||
{
|
||||
long limit = cinfo->mem->max_memory_to_use - already_allocated;
|
||||
long slop, mem;
|
||||
|
||||
/* Don't ask for more than what application has told us we may use */
|
||||
if (max_bytes_needed > limit && limit > 0)
|
||||
max_bytes_needed = limit;
|
||||
/* Find whether there's a big enough free block in the heap.
|
||||
* CompactMem tries to create a contiguous block of the requested size,
|
||||
* and then returns the size of the largest free block (which could be
|
||||
* much more or much less than we asked for).
|
||||
* We add some slop to ensure we don't use up all available memory.
|
||||
*/
|
||||
slop = max_bytes_needed / 16 + 32768L;
|
||||
mem = CompactMem(max_bytes_needed + slop) - slop;
|
||||
if (mem < 0)
|
||||
mem = 0; /* sigh, couldn't even get the slop */
|
||||
/* Don't take more than the application says we can have */
|
||||
if (mem > limit && limit > 0)
|
||||
mem = limit;
|
||||
return mem;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Backing store (temporary file) management.
|
||||
* Backing store objects are only used when the value returned by
|
||||
* jpeg_mem_available is less than the total space needed. You can dispense
|
||||
* with these routines if you have plenty of virtual memory; see jmemnobs.c.
|
||||
*/
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
read_backing_store (j_common_ptr cinfo, backing_store_ptr info,
|
||||
void FAR * buffer_address,
|
||||
long file_offset, long byte_count)
|
||||
{
|
||||
long bytes = byte_count;
|
||||
long retVal;
|
||||
|
||||
if ( SetFPos ( info->temp_file, fsFromStart, file_offset ) != noErr )
|
||||
ERREXIT(cinfo, JERR_TFILE_SEEK);
|
||||
|
||||
retVal = FSRead ( info->temp_file, &bytes,
|
||||
(unsigned char *) buffer_address );
|
||||
if ( retVal != noErr || bytes != byte_count )
|
||||
ERREXIT(cinfo, JERR_TFILE_READ);
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
write_backing_store (j_common_ptr cinfo, backing_store_ptr info,
|
||||
void FAR * buffer_address,
|
||||
long file_offset, long byte_count)
|
||||
{
|
||||
long bytes = byte_count;
|
||||
long retVal;
|
||||
|
||||
if ( SetFPos ( info->temp_file, fsFromStart, file_offset ) != noErr )
|
||||
ERREXIT(cinfo, JERR_TFILE_SEEK);
|
||||
|
||||
retVal = FSWrite ( info->temp_file, &bytes,
|
||||
(unsigned char *) buffer_address );
|
||||
if ( retVal != noErr || bytes != byte_count )
|
||||
ERREXIT(cinfo, JERR_TFILE_WRITE);
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
close_backing_store (j_common_ptr cinfo, backing_store_ptr info)
|
||||
{
|
||||
FSClose ( info->temp_file );
|
||||
FSpDelete ( &(info->tempSpec) );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initial opening of a backing-store object.
|
||||
*
|
||||
* This version uses FindFolder to find the Temporary Items folder,
|
||||
* and puts the temporary file in there.
|
||||
*/
|
||||
|
||||
GLOBAL(void)
|
||||
jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
|
||||
long total_bytes_needed)
|
||||
{
|
||||
short tmpRef, vRefNum;
|
||||
long dirID;
|
||||
FInfo finderInfo;
|
||||
FSSpec theSpec;
|
||||
Str255 fName;
|
||||
OSErr osErr;
|
||||
long gestaltResponse = 0;
|
||||
|
||||
/* Check that FSSpec calls are available. */
|
||||
osErr = Gestalt( gestaltFSAttr, &gestaltResponse );
|
||||
if ( ( osErr != noErr )
|
||||
|| !( gestaltResponse & (1<<gestaltHasFSSpecCalls) ) )
|
||||
ERREXITS(cinfo, JERR_TFILE_CREATE, "- System 7.0 or later required");
|
||||
/* TO DO: add a proper error message to jerror.h. */
|
||||
|
||||
/* Check that FindFolder is available. */
|
||||
osErr = Gestalt( gestaltFindFolderAttr, &gestaltResponse );
|
||||
if ( ( osErr != noErr )
|
||||
|| !( gestaltResponse & (1<<gestaltFindFolderPresent) ) )
|
||||
ERREXITS(cinfo, JERR_TFILE_CREATE, "- System 7.0 or later required.");
|
||||
/* TO DO: add a proper error message to jerror.h. */
|
||||
|
||||
osErr = FindFolder ( kOnSystemDisk, kTemporaryFolderType, kCreateFolder,
|
||||
&vRefNum, &dirID );
|
||||
if ( osErr != noErr )
|
||||
ERREXITS(cinfo, JERR_TFILE_CREATE, "- temporary items folder unavailable");
|
||||
/* TO DO: Try putting the temp files somewhere else. */
|
||||
|
||||
/* Keep generating file names till we find one that's not in use */
|
||||
for (;;) {
|
||||
next_file_num++; /* advance counter */
|
||||
|
||||
sprintf(info->temp_name, TEMP_FILE_NAME, next_file_num);
|
||||
strcpy ( (Ptr)fName+1, info->temp_name );
|
||||
*fName = strlen (info->temp_name);
|
||||
osErr = FSMakeFSSpec ( vRefNum, dirID, fName, &theSpec );
|
||||
|
||||
if ( (osErr = FSpGetFInfo ( &theSpec, &finderInfo ) ) != noErr )
|
||||
break;
|
||||
}
|
||||
|
||||
osErr = FSpCreate ( &theSpec, '????', '????', smSystemScript );
|
||||
if ( osErr != noErr )
|
||||
ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
|
||||
|
||||
osErr = FSpOpenDF ( &theSpec, fsRdWrPerm, &(info->temp_file) );
|
||||
if ( osErr != noErr )
|
||||
ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
|
||||
|
||||
info->tempSpec = theSpec;
|
||||
|
||||
info->read_backing_store = read_backing_store;
|
||||
info->write_backing_store = write_backing_store;
|
||||
info->close_backing_store = close_backing_store;
|
||||
TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* These routines take care of any system-dependent initialization and
|
||||
* cleanup required.
|
||||
*/
|
||||
|
||||
GLOBAL(long)
|
||||
jpeg_mem_init (j_common_ptr cinfo)
|
||||
{
|
||||
next_file_num = 0;
|
||||
|
||||
/* max_memory_to_use will be initialized to FreeMem()'s result;
|
||||
* the calling application might later reduce it, for example
|
||||
* to leave room to invoke multiple JPEG objects.
|
||||
* Note that FreeMem returns the total number of free bytes;
|
||||
* it may not be possible to allocate a single block of this size.
|
||||
*/
|
||||
return FreeMem();
|
||||
}
|
||||
|
||||
GLOBAL(void)
|
||||
jpeg_mem_term (j_common_ptr cinfo)
|
||||
{
|
||||
/* no work */
|
||||
}
|
||||
|
|
@ -1,276 +0,0 @@
|
|||
/*
|
||||
* jmemname.c
|
||||
*
|
||||
* Copyright (C) 1992-1997, 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 provides a generic implementation of the system-dependent
|
||||
* portion of the JPEG memory manager. This implementation assumes that
|
||||
* you must explicitly construct a name for each temp file.
|
||||
* Also, the problem of determining the amount of memory available
|
||||
* is shoved onto the user.
|
||||
*/
|
||||
|
||||
#define JPEG_INTERNALS
|
||||
#include "jinclude.h"
|
||||
#include "jpeglib.h"
|
||||
#include "jmemsys.h" /* import the system-dependent declarations */
|
||||
|
||||
#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */
|
||||
extern void * malloc JPP((size_t size));
|
||||
extern void free JPP((void *ptr));
|
||||
#endif
|
||||
|
||||
#ifndef SEEK_SET /* pre-ANSI systems may not define this; */
|
||||
#define SEEK_SET 0 /* if not, assume 0 is correct */
|
||||
#endif
|
||||
|
||||
#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */
|
||||
#define READ_BINARY "r"
|
||||
#define RW_BINARY "w+"
|
||||
#else
|
||||
#ifdef VMS /* VMS is very nonstandard */
|
||||
#define READ_BINARY "rb", "ctx=stm"
|
||||
#define RW_BINARY "w+b", "ctx=stm"
|
||||
#else /* standard ANSI-compliant case */
|
||||
#define READ_BINARY "rb"
|
||||
#define RW_BINARY "w+b"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Selection of a file name for a temporary file.
|
||||
* This is system-dependent!
|
||||
*
|
||||
* The code as given is suitable for most Unix systems, and it is easily
|
||||
* modified for most non-Unix systems. Some notes:
|
||||
* 1. The temp file is created in the directory named by TEMP_DIRECTORY.
|
||||
* The default value is /usr/tmp, which is the conventional place for
|
||||
* creating large temp files on Unix. On other systems you'll probably
|
||||
* want to change the file location. You can do this by editing the
|
||||
* #define, or (preferred) by defining TEMP_DIRECTORY in jconfig.h.
|
||||
*
|
||||
* 2. If you need to change the file name as well as its location,
|
||||
* you can override the TEMP_FILE_NAME macro. (Note that this is
|
||||
* actually a printf format string; it must contain %s and %d.)
|
||||
* Few people should need to do this.
|
||||
*
|
||||
* 3. mktemp() is used to ensure that multiple processes running
|
||||
* simultaneously won't select the same file names. If your system
|
||||
* doesn't have mktemp(), define NO_MKTEMP to do it the hard way.
|
||||
* (If you don't have <errno.h>, also define NO_ERRNO_H.)
|
||||
*
|
||||
* 4. You probably want to define NEED_SIGNAL_CATCHER so that cjpeg.c/djpeg.c
|
||||
* will cause the temp files to be removed if you stop the program early.
|
||||
*/
|
||||
|
||||
#ifndef TEMP_DIRECTORY /* can override from jconfig.h or Makefile */
|
||||
#define TEMP_DIRECTORY "/usr/tmp/" /* recommended setting for Unix */
|
||||
#endif
|
||||
|
||||
static int next_file_num; /* to distinguish among several temp files */
|
||||
|
||||
#ifdef NO_MKTEMP
|
||||
|
||||
#ifndef TEMP_FILE_NAME /* can override from jconfig.h or Makefile */
|
||||
#define TEMP_FILE_NAME "%sJPG%03d.TMP"
|
||||
#endif
|
||||
|
||||
#ifndef NO_ERRNO_H
|
||||
#include <errno.h> /* to define ENOENT */
|
||||
#endif
|
||||
|
||||
/* ANSI C specifies that errno is a macro, but on older systems it's more
|
||||
* likely to be a plain int variable. And not all versions of errno.h
|
||||
* bother to declare it, so we have to in order to be most portable. Thus:
|
||||
*/
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
select_file_name (char * fname)
|
||||
{
|
||||
FILE * tfile;
|
||||
|
||||
/* Keep generating file names till we find one that's not in use */
|
||||
for (;;) {
|
||||
next_file_num++; /* advance counter */
|
||||
sprintf(fname, TEMP_FILE_NAME, TEMP_DIRECTORY, next_file_num);
|
||||
if ((tfile = fopen(fname, READ_BINARY)) == NULL) {
|
||||
/* fopen could have failed for a reason other than the file not
|
||||
* being there; for example, file there but unreadable.
|
||||
* If <errno.h> isn't available, then we cannot test the cause.
|
||||
*/
|
||||
#ifdef ENOENT
|
||||
if (errno != ENOENT)
|
||||
continue;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
fclose(tfile); /* oops, it's there; close tfile & try again */
|
||||
}
|
||||
}
|
||||
|
||||
#else /* ! NO_MKTEMP */
|
||||
|
||||
/* Note that mktemp() requires the initial filename to end in six X's */
|
||||
#ifndef TEMP_FILE_NAME /* can override from jconfig.h or Makefile */
|
||||
#define TEMP_FILE_NAME "%sJPG%dXXXXXX"
|
||||
#endif
|
||||
|
||||
LOCAL(void)
|
||||
select_file_name (char * fname)
|
||||
{
|
||||
next_file_num++; /* advance counter */
|
||||
sprintf(fname, TEMP_FILE_NAME, TEMP_DIRECTORY, next_file_num);
|
||||
mktemp(fname); /* make sure file name is unique */
|
||||
/* mktemp replaces the trailing XXXXXX with a unique string of characters */
|
||||
}
|
||||
|
||||
#endif /* NO_MKTEMP */
|
||||
|
||||
|
||||
/*
|
||||
* Memory allocation and freeing are controlled by the regular library
|
||||
* routines malloc() and free().
|
||||
*/
|
||||
|
||||
GLOBAL(void *)
|
||||
jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
|
||||
{
|
||||
return (void *) malloc(sizeofobject);
|
||||
}
|
||||
|
||||
GLOBAL(void)
|
||||
jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
|
||||
{
|
||||
free(object);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* "Large" objects are treated the same as "small" ones.
|
||||
* NB: although we include FAR keywords in the routine declarations,
|
||||
* this file won't actually work in 80x86 small/medium model; at least,
|
||||
* you probably won't be able to process useful-size images in only 64KB.
|
||||
*/
|
||||
|
||||
GLOBAL(void FAR *)
|
||||
jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
|
||||
{
|
||||
return (void FAR *) malloc(sizeofobject);
|
||||
}
|
||||
|
||||
GLOBAL(void)
|
||||
jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
|
||||
{
|
||||
free(object);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This routine computes the total memory space available for allocation.
|
||||
* It's impossible to do this in a portable way; our current solution is
|
||||
* to make the user tell us (with a default value set at compile time).
|
||||
* If you can actually get the available space, it's a good idea to subtract
|
||||
* a slop factor of 5% or so.
|
||||
*/
|
||||
|
||||
#ifndef DEFAULT_MAX_MEM /* so can override from makefile */
|
||||
#define DEFAULT_MAX_MEM 1000000L /* default: one megabyte */
|
||||
#endif
|
||||
|
||||
GLOBAL(long)
|
||||
jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
|
||||
long max_bytes_needed, long already_allocated)
|
||||
{
|
||||
return cinfo->mem->max_memory_to_use - already_allocated;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Backing store (temporary file) management.
|
||||
* Backing store objects are only used when the value returned by
|
||||
* jpeg_mem_available is less than the total space needed. You can dispense
|
||||
* with these routines if you have plenty of virtual memory; see jmemnobs.c.
|
||||
*/
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
read_backing_store (j_common_ptr cinfo, backing_store_ptr info,
|
||||
void FAR * buffer_address,
|
||||
long file_offset, long byte_count)
|
||||
{
|
||||
if (fseek(info->temp_file, file_offset, SEEK_SET))
|
||||
ERREXIT(cinfo, JERR_TFILE_SEEK);
|
||||
if (JFREAD(info->temp_file, buffer_address, byte_count)
|
||||
!= (size_t) byte_count)
|
||||
ERREXIT(cinfo, JERR_TFILE_READ);
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
write_backing_store (j_common_ptr cinfo, backing_store_ptr info,
|
||||
void FAR * buffer_address,
|
||||
long file_offset, long byte_count)
|
||||
{
|
||||
if (fseek(info->temp_file, file_offset, SEEK_SET))
|
||||
ERREXIT(cinfo, JERR_TFILE_SEEK);
|
||||
if (JFWRITE(info->temp_file, buffer_address, byte_count)
|
||||
!= (size_t) byte_count)
|
||||
ERREXIT(cinfo, JERR_TFILE_WRITE);
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
close_backing_store (j_common_ptr cinfo, backing_store_ptr info)
|
||||
{
|
||||
fclose(info->temp_file); /* close the file */
|
||||
unlink(info->temp_name); /* delete the file */
|
||||
/* If your system doesn't have unlink(), use remove() instead.
|
||||
* remove() is the ANSI-standard name for this function, but if
|
||||
* your system was ANSI you'd be using jmemansi.c, right?
|
||||
*/
|
||||
TRACEMSS(cinfo, 1, JTRC_TFILE_CLOSE, info->temp_name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initial opening of a backing-store object.
|
||||
*/
|
||||
|
||||
GLOBAL(void)
|
||||
jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
|
||||
long total_bytes_needed)
|
||||
{
|
||||
select_file_name(info->temp_name);
|
||||
if ((info->temp_file = fopen(info->temp_name, RW_BINARY)) == NULL)
|
||||
ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
|
||||
info->read_backing_store = read_backing_store;
|
||||
info->write_backing_store = write_backing_store;
|
||||
info->close_backing_store = close_backing_store;
|
||||
TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* These routines take care of any system-dependent initialization and
|
||||
* cleanup required.
|
||||
*/
|
||||
|
||||
GLOBAL(long)
|
||||
jpeg_mem_init (j_common_ptr cinfo)
|
||||
{
|
||||
next_file_num = 0; /* initialize temp file name generator */
|
||||
return DEFAULT_MAX_MEM; /* default for max_memory_to_use */
|
||||
}
|
||||
|
||||
GLOBAL(void)
|
||||
jpeg_mem_term (j_common_ptr cinfo)
|
||||
{
|
||||
/* no work */
|
||||
}
|
||||
|
|
@ -1,469 +0,0 @@
|
|||
/*
|
||||
* rdbmp.c
|
||||
*
|
||||
* Copyright (C) 1994-1996, Thomas G. Lane.
|
||||
* Modified 2009-2019 by Guido Vollbeding.
|
||||
* 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 routines to read input images in Microsoft "BMP"
|
||||
* format (MS Windows 3.x, OS/2 1.x, and OS/2 2.x flavors).
|
||||
* Currently, only 8-, 24-, and 32-bit images are supported, not 1-bit or
|
||||
* 4-bit (feeding such low-depth images into JPEG would be silly anyway).
|
||||
* Also, we don't support RLE-compressed files.
|
||||
*
|
||||
* These routines may need modification for non-Unix environments or
|
||||
* specialized applications. As they stand, they assume input from
|
||||
* an ordinary stdio stream. They further assume that reading begins
|
||||
* at the start of the file; start_input may need work if the
|
||||
* user interface has already read some data (e.g., to determine that
|
||||
* the file is indeed BMP format).
|
||||
*
|
||||
* This code contributed by James Arthur Boucher.
|
||||
*/
|
||||
|
||||
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
||||
|
||||
#ifdef BMP_SUPPORTED
|
||||
|
||||
|
||||
/* Macros to deal with unsigned chars as efficiently as compiler allows */
|
||||
|
||||
#ifdef HAVE_UNSIGNED_CHAR
|
||||
typedef unsigned char U_CHAR;
|
||||
#define UCH(x) ((int) (x))
|
||||
#else /* !HAVE_UNSIGNED_CHAR */
|
||||
typedef char U_CHAR;
|
||||
#ifdef CHAR_IS_UNSIGNED
|
||||
#define UCH(x) ((int) (x))
|
||||
#else
|
||||
#define UCH(x) ((int) (x) & 0xFF)
|
||||
#endif
|
||||
#endif /* HAVE_UNSIGNED_CHAR */
|
||||
|
||||
|
||||
#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
|
||||
|
||||
|
||||
/* Private version of data source object */
|
||||
|
||||
typedef struct _bmp_source_struct * bmp_source_ptr;
|
||||
|
||||
typedef struct _bmp_source_struct {
|
||||
struct cjpeg_source_struct pub; /* public fields */
|
||||
|
||||
j_compress_ptr cinfo; /* back link saves passing separate parm */
|
||||
|
||||
JSAMPARRAY colormap; /* BMP colormap (converted to my format) */
|
||||
|
||||
jvirt_sarray_ptr whole_image; /* Needed to reverse row order */
|
||||
JDIMENSION source_row; /* Current source row number */
|
||||
JDIMENSION row_width; /* Physical width of scanlines in file */
|
||||
|
||||
int bits_per_pixel; /* remembers 8-, 24-, or 32-bit format */
|
||||
int cmap_length; /* colormap length */
|
||||
} bmp_source_struct;
|
||||
|
||||
|
||||
LOCAL(int)
|
||||
read_byte (bmp_source_ptr sinfo)
|
||||
/* Read next byte from BMP file */
|
||||
{
|
||||
register FILE *infile = sinfo->pub.input_file;
|
||||
register int c;
|
||||
|
||||
if ((c = getc(infile)) == EOF)
|
||||
ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
read_colormap (bmp_source_ptr sinfo, int cmaplen, int mapentrysize)
|
||||
/* Read the colormap from a BMP file */
|
||||
{
|
||||
int i;
|
||||
|
||||
switch (mapentrysize) {
|
||||
case 3:
|
||||
/* BGR format (occurs in OS/2 files) */
|
||||
for (i = 0; i < cmaplen; i++) {
|
||||
sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo);
|
||||
sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo);
|
||||
sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
/* BGR0 format (occurs in MS Windows files) */
|
||||
for (i = 0; i < cmaplen; i++) {
|
||||
sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo);
|
||||
sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo);
|
||||
sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo);
|
||||
(void) read_byte(sinfo);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERREXIT(sinfo->cinfo, JERR_BMP_BADCMAP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read one row of pixels.
|
||||
* The image has been read into the whole_image array, but is otherwise
|
||||
* unprocessed. We must read it out in top-to-bottom row order, and if
|
||||
* it is an 8-bit image, we must expand colormapped pixels to 24bit format.
|
||||
*/
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
get_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
/* This version is for reading 8-bit colormap indexes */
|
||||
{
|
||||
bmp_source_ptr source = (bmp_source_ptr) sinfo;
|
||||
register JSAMPROW inptr, outptr;
|
||||
register JSAMPARRAY colormap;
|
||||
register JDIMENSION col;
|
||||
register int t;
|
||||
int cmaplen;
|
||||
|
||||
/* Fetch next row from virtual array */
|
||||
source->source_row--;
|
||||
inptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,
|
||||
source->whole_image, source->source_row, (JDIMENSION) 1, FALSE);
|
||||
|
||||
/* Expand the colormap indexes to real data */
|
||||
outptr = source->pub.buffer[0];
|
||||
colormap = source->colormap;
|
||||
cmaplen = source->cmap_length;
|
||||
for (col = cinfo->image_width; col > 0; col--) {
|
||||
t = GETJSAMPLE(*inptr++);
|
||||
if (t >= cmaplen)
|
||||
ERREXIT(cinfo, JERR_BMP_OUTOFRANGE);
|
||||
*outptr++ = colormap[0][t]; /* can omit GETJSAMPLE() safely */
|
||||
*outptr++ = colormap[1][t];
|
||||
*outptr++ = colormap[2][t];
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
/* This version is for reading 24-bit pixels */
|
||||
{
|
||||
bmp_source_ptr source = (bmp_source_ptr) sinfo;
|
||||
register JSAMPROW inptr, outptr;
|
||||
register JDIMENSION col;
|
||||
|
||||
/* Fetch next row from virtual array */
|
||||
source->source_row--;
|
||||
inptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,
|
||||
source->whole_image, source->source_row, (JDIMENSION) 1, FALSE);
|
||||
|
||||
/* Transfer data. Note source values are in BGR order
|
||||
* (even though Microsoft's own documents say the opposite).
|
||||
*/
|
||||
outptr = source->pub.buffer[0];
|
||||
for (col = cinfo->image_width; col > 0; col--) {
|
||||
outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */
|
||||
outptr[1] = *inptr++;
|
||||
outptr[0] = *inptr++;
|
||||
outptr += 3;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
get_32bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
/* This version is for reading 32-bit pixels */
|
||||
{
|
||||
bmp_source_ptr source = (bmp_source_ptr) sinfo;
|
||||
register JSAMPROW inptr, outptr;
|
||||
register JDIMENSION col;
|
||||
|
||||
/* Fetch next row from virtual array */
|
||||
source->source_row--;
|
||||
inptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,
|
||||
source->whole_image, source->source_row, (JDIMENSION) 1, FALSE);
|
||||
|
||||
/* Transfer data. Note source values are in BGR order
|
||||
* (even though Microsoft's own documents say the opposite).
|
||||
*/
|
||||
outptr = source->pub.buffer[0];
|
||||
for (col = cinfo->image_width; col > 0; col--) {
|
||||
outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */
|
||||
outptr[1] = *inptr++;
|
||||
outptr[0] = *inptr++;
|
||||
inptr++; /* skip the 4th byte (Alpha channel) */
|
||||
outptr += 3;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This method loads the image into whole_image during the first call on
|
||||
* get_pixel_rows. The get_pixel_rows pointer is then adjusted to call
|
||||
* get_8bit_row, get_24bit_row, or get_32bit_row on subsequent calls.
|
||||
*/
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
preload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
{
|
||||
bmp_source_ptr source = (bmp_source_ptr) sinfo;
|
||||
register FILE *infile = source->pub.input_file;
|
||||
register int c;
|
||||
register JSAMPROW out_ptr;
|
||||
JDIMENSION row, col;
|
||||
cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
|
||||
|
||||
/* Read the data into a virtual array in input-file row order. */
|
||||
for (row = 0; row < cinfo->image_height; row++) {
|
||||
if (progress != NULL) {
|
||||
progress->pub.pass_counter = (long) row;
|
||||
progress->pub.pass_limit = (long) cinfo->image_height;
|
||||
(*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
|
||||
}
|
||||
out_ptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,
|
||||
source->whole_image, row, (JDIMENSION) 1, TRUE);
|
||||
for (col = source->row_width; col > 0; col--) {
|
||||
/* inline copy of read_byte() for speed */
|
||||
if ((c = getc(infile)) == EOF)
|
||||
ERREXIT(cinfo, JERR_INPUT_EOF);
|
||||
*out_ptr++ = (JSAMPLE) c;
|
||||
}
|
||||
}
|
||||
if (progress != NULL)
|
||||
progress->completed_extra_passes++;
|
||||
|
||||
/* Set up to read from the virtual array in top-to-bottom order */
|
||||
switch (source->bits_per_pixel) {
|
||||
case 8:
|
||||
source->pub.get_pixel_rows = get_8bit_row;
|
||||
break;
|
||||
case 24:
|
||||
source->pub.get_pixel_rows = get_24bit_row;
|
||||
break;
|
||||
case 32:
|
||||
source->pub.get_pixel_rows = get_32bit_row;
|
||||
break;
|
||||
default:
|
||||
ERREXIT(cinfo, JERR_BMP_BADDEPTH);
|
||||
}
|
||||
source->source_row = cinfo->image_height;
|
||||
|
||||
/* And read the first row */
|
||||
return (*source->pub.get_pixel_rows) (cinfo, sinfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read the file header; return image size and component count.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
start_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
{
|
||||
bmp_source_ptr source = (bmp_source_ptr) sinfo;
|
||||
U_CHAR bmpfileheader[14];
|
||||
U_CHAR bmpinfoheader[64];
|
||||
#define GET_2B(array, offset) ((unsigned int) UCH(array[offset]) + \
|
||||
(((unsigned int) UCH(array[offset+1])) << 8))
|
||||
#define GET_4B(array, offset) ((INT32) UCH(array[offset]) + \
|
||||
(((INT32) UCH(array[offset+1])) << 8) + \
|
||||
(((INT32) UCH(array[offset+2])) << 16) + \
|
||||
(((INT32) UCH(array[offset+3])) << 24))
|
||||
INT32 bfOffBits;
|
||||
INT32 headerSize;
|
||||
INT32 biWidth;
|
||||
INT32 biHeight;
|
||||
unsigned int biPlanes;
|
||||
INT32 biCompression;
|
||||
INT32 biXPelsPerMeter,biYPelsPerMeter;
|
||||
INT32 biClrUsed = 0;
|
||||
int mapentrysize = 0; /* 0 indicates no colormap */
|
||||
INT32 bPad;
|
||||
JDIMENSION row_width;
|
||||
|
||||
/* Read and verify the bitmap file header */
|
||||
if (! ReadOK(source->pub.input_file, bmpfileheader, 14))
|
||||
ERREXIT(cinfo, JERR_INPUT_EOF);
|
||||
if (GET_2B(bmpfileheader, 0) != 0x4D42) /* 'BM' */
|
||||
ERREXIT(cinfo, JERR_BMP_NOT);
|
||||
bfOffBits = GET_4B(bmpfileheader, 10);
|
||||
/* We ignore the remaining fileheader fields */
|
||||
|
||||
/* The infoheader might be 12 bytes (OS/2 1.x), 40 bytes (Windows),
|
||||
* or 64 bytes (OS/2 2.x). Check the first 4 bytes to find out which.
|
||||
*/
|
||||
if (! ReadOK(source->pub.input_file, bmpinfoheader, 4))
|
||||
ERREXIT(cinfo, JERR_INPUT_EOF);
|
||||
headerSize = GET_4B(bmpinfoheader, 0);
|
||||
if (headerSize < 12 || headerSize > 64)
|
||||
ERREXIT(cinfo, JERR_BMP_BADHEADER);
|
||||
if (! ReadOK(source->pub.input_file, bmpinfoheader + 4, headerSize - 4))
|
||||
ERREXIT(cinfo, JERR_INPUT_EOF);
|
||||
|
||||
switch ((int) headerSize) {
|
||||
case 12:
|
||||
/* Decode OS/2 1.x header (Microsoft calls this a BITMAPCOREHEADER) */
|
||||
biWidth = (INT32) GET_2B(bmpinfoheader, 4);
|
||||
biHeight = (INT32) GET_2B(bmpinfoheader, 6);
|
||||
biPlanes = GET_2B(bmpinfoheader, 8);
|
||||
source->bits_per_pixel = (int) GET_2B(bmpinfoheader, 10);
|
||||
|
||||
switch (source->bits_per_pixel) {
|
||||
case 8: /* colormapped image */
|
||||
mapentrysize = 3; /* OS/2 uses RGBTRIPLE colormap */
|
||||
TRACEMS2(cinfo, 1, JTRC_BMP_OS2_MAPPED, (int) biWidth, (int) biHeight);
|
||||
break;
|
||||
case 24: /* RGB image */
|
||||
case 32: /* RGB image + Alpha channel */
|
||||
TRACEMS3(cinfo, 1, JTRC_BMP_OS2, (int) biWidth, (int) biHeight,
|
||||
source->bits_per_pixel);
|
||||
break;
|
||||
default:
|
||||
ERREXIT(cinfo, JERR_BMP_BADDEPTH);
|
||||
}
|
||||
break;
|
||||
case 40:
|
||||
case 64:
|
||||
/* Decode Windows 3.x header (Microsoft calls this a BITMAPINFOHEADER) */
|
||||
/* or OS/2 2.x header, which has additional fields that we ignore */
|
||||
biWidth = GET_4B(bmpinfoheader, 4);
|
||||
biHeight = GET_4B(bmpinfoheader, 8);
|
||||
biPlanes = GET_2B(bmpinfoheader, 12);
|
||||
source->bits_per_pixel = (int) GET_2B(bmpinfoheader, 14);
|
||||
biCompression = GET_4B(bmpinfoheader, 16);
|
||||
biXPelsPerMeter = GET_4B(bmpinfoheader, 24);
|
||||
biYPelsPerMeter = GET_4B(bmpinfoheader, 28);
|
||||
biClrUsed = GET_4B(bmpinfoheader, 32);
|
||||
/* biSizeImage, biClrImportant fields are ignored */
|
||||
|
||||
switch (source->bits_per_pixel) {
|
||||
case 8: /* colormapped image */
|
||||
mapentrysize = 4; /* Windows uses RGBQUAD colormap */
|
||||
TRACEMS2(cinfo, 1, JTRC_BMP_MAPPED, (int) biWidth, (int) biHeight);
|
||||
break;
|
||||
case 24: /* RGB image */
|
||||
case 32: /* RGB image + Alpha channel */
|
||||
TRACEMS3(cinfo, 1, JTRC_BMP, (int) biWidth, (int) biHeight,
|
||||
source->bits_per_pixel);
|
||||
break;
|
||||
default:
|
||||
ERREXIT(cinfo, JERR_BMP_BADDEPTH);
|
||||
}
|
||||
if (biCompression != 0)
|
||||
ERREXIT(cinfo, JERR_BMP_COMPRESSED);
|
||||
|
||||
if (biXPelsPerMeter > 0 && biYPelsPerMeter > 0) {
|
||||
/* Set JFIF density parameters from the BMP data */
|
||||
cinfo->X_density = (UINT16) (biXPelsPerMeter/100); /* 100 cm per meter */
|
||||
cinfo->Y_density = (UINT16) (biYPelsPerMeter/100);
|
||||
cinfo->density_unit = 2; /* dots/cm */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERREXIT(cinfo, JERR_BMP_BADHEADER);
|
||||
return; /* avoid compiler warnings for uninitialized variables */
|
||||
}
|
||||
|
||||
if (biPlanes != 1)
|
||||
ERREXIT(cinfo, JERR_BMP_BADPLANES);
|
||||
/* Sanity check for buffer allocation below */
|
||||
if (biWidth <= 0 || biHeight <= 0 || (biWidth >> 24) || (biHeight >> 24))
|
||||
ERREXIT(cinfo, JERR_BMP_OUTOFRANGE);
|
||||
|
||||
/* Compute distance to bitmap data --- will adjust for colormap below */
|
||||
bPad = bfOffBits - (headerSize + 14);
|
||||
|
||||
/* Read the colormap, if any */
|
||||
if (mapentrysize > 0) {
|
||||
if (biClrUsed <= 0)
|
||||
biClrUsed = 256; /* assume it's 256 */
|
||||
else if (biClrUsed > 256)
|
||||
ERREXIT(cinfo, JERR_BMP_BADCMAP);
|
||||
/* Allocate space to store the colormap */
|
||||
source->colormap = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo,
|
||||
JPOOL_IMAGE, (JDIMENSION) biClrUsed, (JDIMENSION) 3);
|
||||
source->cmap_length = (int) biClrUsed;
|
||||
/* and read it from the file */
|
||||
read_colormap(source, (int) biClrUsed, mapentrysize);
|
||||
/* account for size of colormap */
|
||||
bPad -= biClrUsed * mapentrysize;
|
||||
}
|
||||
|
||||
/* Skip any remaining pad bytes */
|
||||
if (bPad < 0) /* incorrect bfOffBits value? */
|
||||
ERREXIT(cinfo, JERR_BMP_BADHEADER);
|
||||
while (--bPad >= 0) {
|
||||
(void) read_byte(source);
|
||||
}
|
||||
|
||||
/* Compute row width in file, including padding to 4-byte boundary */
|
||||
if (source->bits_per_pixel == 24)
|
||||
row_width = (JDIMENSION) (biWidth * 3);
|
||||
else if (source->bits_per_pixel == 32)
|
||||
row_width = (JDIMENSION) (biWidth * 4);
|
||||
else
|
||||
row_width = (JDIMENSION) biWidth;
|
||||
while ((row_width & 3) != 0) row_width++;
|
||||
source->row_width = row_width;
|
||||
|
||||
/* Allocate space for inversion array, prepare for preload pass */
|
||||
source->whole_image = (*cinfo->mem->request_virt_sarray)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
|
||||
row_width, (JDIMENSION) biHeight, (JDIMENSION) 1);
|
||||
source->pub.get_pixel_rows = preload_image;
|
||||
if (cinfo->progress != NULL) {
|
||||
cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
|
||||
progress->total_extra_passes++; /* count file input as separate pass */
|
||||
}
|
||||
|
||||
/* Allocate one-row buffer for returned data */
|
||||
source->pub.buffer = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo,
|
||||
JPOOL_IMAGE, (JDIMENSION) (biWidth * 3), (JDIMENSION) 1);
|
||||
source->pub.buffer_height = 1;
|
||||
|
||||
cinfo->in_color_space = JCS_RGB;
|
||||
cinfo->input_components = 3;
|
||||
cinfo->data_precision = 8;
|
||||
cinfo->image_width = (JDIMENSION) biWidth;
|
||||
cinfo->image_height = (JDIMENSION) biHeight;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Finish up at the end of the file.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
finish_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
{
|
||||
/* no work */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The module selection routine for BMP format input.
|
||||
*/
|
||||
|
||||
GLOBAL(cjpeg_source_ptr)
|
||||
jinit_read_bmp (j_compress_ptr cinfo)
|
||||
{
|
||||
bmp_source_ptr source;
|
||||
|
||||
/* Create module interface object */
|
||||
source = (bmp_source_ptr) (*cinfo->mem->alloc_small)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(bmp_source_struct));
|
||||
source->cinfo = cinfo; /* make back link for subroutines */
|
||||
/* Fill in method ptrs, except get_pixel_rows which start_input sets */
|
||||
source->pub.start_input = start_input_bmp;
|
||||
source->pub.finish_input = finish_input_bmp;
|
||||
|
||||
return &source->pub;
|
||||
}
|
||||
|
||||
#endif /* BMP_SUPPORTED */
|
||||
|
|
@ -1,253 +0,0 @@
|
|||
/*
|
||||
* rdcolmap.c
|
||||
*
|
||||
* Copyright (C) 1994-1996, 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 implements djpeg's "-map file" switch. It reads a source image
|
||||
* and constructs a colormap to be supplied to the JPEG decompressor.
|
||||
*
|
||||
* Currently, these file formats are supported for the map file:
|
||||
* GIF: the contents of the GIF's global colormap are used.
|
||||
* PPM (either text or raw flavor): the entire file is read and
|
||||
* each unique pixel value is entered in the map.
|
||||
* Note that reading a large PPM file will be horrendously slow.
|
||||
* Typically, a PPM-format map file should contain just one pixel
|
||||
* of each desired color. Such a file can be extracted from an
|
||||
* ordinary image PPM file with ppmtomap(1).
|
||||
*
|
||||
* Rescaling a PPM that has a maxval unequal to MAXJSAMPLE is not
|
||||
* currently implemented.
|
||||
*/
|
||||
|
||||
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
||||
|
||||
#ifdef QUANT_2PASS_SUPPORTED /* otherwise can't quantize to supplied map */
|
||||
|
||||
/* Portions of this code are based on the PBMPLUS library, which is:
|
||||
**
|
||||
** Copyright (C) 1988 by Jef Poskanzer.
|
||||
**
|
||||
** Permission to use, copy, modify, and distribute this software and its
|
||||
** documentation for any purpose and without fee is hereby granted, provided
|
||||
** that the above copyright notice appear in all copies and that both that
|
||||
** copyright notice and this permission notice appear in supporting
|
||||
** documentation. This software is provided "as is" without express or
|
||||
** implied warranty.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Add a (potentially) new color to the color map.
|
||||
*/
|
||||
|
||||
LOCAL(void)
|
||||
add_map_entry (j_decompress_ptr cinfo, int R, int G, int B)
|
||||
{
|
||||
JSAMPROW colormap0 = cinfo->colormap[0];
|
||||
JSAMPROW colormap1 = cinfo->colormap[1];
|
||||
JSAMPROW colormap2 = cinfo->colormap[2];
|
||||
int ncolors = cinfo->actual_number_of_colors;
|
||||
int index;
|
||||
|
||||
/* Check for duplicate color. */
|
||||
for (index = 0; index < ncolors; index++) {
|
||||
if (GETJSAMPLE(colormap0[index]) == R &&
|
||||
GETJSAMPLE(colormap1[index]) == G &&
|
||||
GETJSAMPLE(colormap2[index]) == B)
|
||||
return; /* color is already in map */
|
||||
}
|
||||
|
||||
/* Check for map overflow. */
|
||||
if (ncolors >= (MAXJSAMPLE+1))
|
||||
ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, (MAXJSAMPLE+1));
|
||||
|
||||
/* OK, add color to map. */
|
||||
colormap0[ncolors] = (JSAMPLE) R;
|
||||
colormap1[ncolors] = (JSAMPLE) G;
|
||||
colormap2[ncolors] = (JSAMPLE) B;
|
||||
cinfo->actual_number_of_colors++;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Extract color map from a GIF file.
|
||||
*/
|
||||
|
||||
LOCAL(void)
|
||||
read_gif_map (j_decompress_ptr cinfo, FILE * infile)
|
||||
{
|
||||
int header[13];
|
||||
int i, colormaplen;
|
||||
int R, G, B;
|
||||
|
||||
/* Initial 'G' has already been read by read_color_map */
|
||||
/* Read the rest of the GIF header and logical screen descriptor */
|
||||
for (i = 1; i < 13; i++) {
|
||||
if ((header[i] = getc(infile)) == EOF)
|
||||
ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
|
||||
}
|
||||
|
||||
/* Verify GIF Header */
|
||||
if (header[1] != 'I' || header[2] != 'F')
|
||||
ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
|
||||
|
||||
/* There must be a global color map. */
|
||||
if ((header[10] & 0x80) == 0)
|
||||
ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
|
||||
|
||||
/* OK, fetch it. */
|
||||
colormaplen = 2 << (header[10] & 0x07);
|
||||
|
||||
for (i = 0; i < colormaplen; i++) {
|
||||
R = getc(infile);
|
||||
G = getc(infile);
|
||||
B = getc(infile);
|
||||
if (R == EOF || G == EOF || B == EOF)
|
||||
ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
|
||||
add_map_entry(cinfo,
|
||||
R << (BITS_IN_JSAMPLE-8),
|
||||
G << (BITS_IN_JSAMPLE-8),
|
||||
B << (BITS_IN_JSAMPLE-8));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Support routines for reading PPM */
|
||||
|
||||
|
||||
LOCAL(int)
|
||||
pbm_getc (FILE * infile)
|
||||
/* Read next char, skipping over any comments */
|
||||
/* A comment/newline sequence is returned as a newline */
|
||||
{
|
||||
register int ch;
|
||||
|
||||
ch = getc(infile);
|
||||
if (ch == '#') {
|
||||
do {
|
||||
ch = getc(infile);
|
||||
} while (ch != '\n' && ch != EOF);
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
|
||||
LOCAL(unsigned int)
|
||||
read_pbm_integer (j_decompress_ptr cinfo, FILE * infile)
|
||||
/* Read an unsigned decimal integer from the PPM file */
|
||||
/* Swallows one trailing character after the integer */
|
||||
/* Note that on a 16-bit-int machine, only values up to 64k can be read. */
|
||||
/* This should not be a problem in practice. */
|
||||
{
|
||||
register int ch;
|
||||
register unsigned int val;
|
||||
|
||||
/* Skip any leading whitespace */
|
||||
do {
|
||||
ch = pbm_getc(infile);
|
||||
if (ch == EOF)
|
||||
ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
|
||||
} while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
|
||||
|
||||
if (ch < '0' || ch > '9')
|
||||
ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
|
||||
|
||||
val = ch - '0';
|
||||
while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') {
|
||||
val *= 10;
|
||||
val += ch - '0';
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Extract color map from a PPM file.
|
||||
*/
|
||||
|
||||
LOCAL(void)
|
||||
read_ppm_map (j_decompress_ptr cinfo, FILE * infile)
|
||||
{
|
||||
int c;
|
||||
unsigned int w, h, maxval, row, col;
|
||||
int R, G, B;
|
||||
|
||||
/* Initial 'P' has already been read by read_color_map */
|
||||
c = getc(infile); /* save format discriminator for a sec */
|
||||
|
||||
/* while we fetch the remaining header info */
|
||||
w = read_pbm_integer(cinfo, infile);
|
||||
h = read_pbm_integer(cinfo, infile);
|
||||
maxval = read_pbm_integer(cinfo, infile);
|
||||
|
||||
if (w <= 0 || h <= 0 || maxval <= 0) /* error check */
|
||||
ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
|
||||
|
||||
/* For now, we don't support rescaling from an unusual maxval. */
|
||||
if (maxval != (unsigned int) MAXJSAMPLE)
|
||||
ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
|
||||
|
||||
switch (c) {
|
||||
case '3': /* it's a text-format PPM file */
|
||||
for (row = 0; row < h; row++) {
|
||||
for (col = 0; col < w; col++) {
|
||||
R = read_pbm_integer(cinfo, infile);
|
||||
G = read_pbm_integer(cinfo, infile);
|
||||
B = read_pbm_integer(cinfo, infile);
|
||||
add_map_entry(cinfo, R, G, B);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case '6': /* it's a raw-format PPM file */
|
||||
for (row = 0; row < h; row++) {
|
||||
for (col = 0; col < w; col++) {
|
||||
R = getc(infile);
|
||||
G = getc(infile);
|
||||
B = getc(infile);
|
||||
if (R == EOF || G == EOF || B == EOF)
|
||||
ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
|
||||
add_map_entry(cinfo, R, G, B);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Main entry point from djpeg.c.
|
||||
* Input: opened input file (from file name argument on command line).
|
||||
* Output: colormap and actual_number_of_colors fields are set in cinfo.
|
||||
*/
|
||||
|
||||
GLOBAL(void)
|
||||
read_color_map (j_decompress_ptr cinfo, FILE * infile)
|
||||
{
|
||||
/* Allocate space for a color map of maximum supported size. */
|
||||
cinfo->colormap = (*cinfo->mem->alloc_sarray)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE,
|
||||
(JDIMENSION) (MAXJSAMPLE+1), (JDIMENSION) 3);
|
||||
cinfo->actual_number_of_colors = 0; /* initialize map to empty */
|
||||
|
||||
/* Read first byte to determine file format */
|
||||
switch (getc(infile)) {
|
||||
case 'G':
|
||||
read_gif_map(cinfo, infile);
|
||||
break;
|
||||
case 'P':
|
||||
read_ppm_map(cinfo, infile);
|
||||
break;
|
||||
default:
|
||||
ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* QUANT_2PASS_SUPPORTED */
|
||||
|
|
@ -1,679 +0,0 @@
|
|||
/*
|
||||
* rdgif.c
|
||||
*
|
||||
* Copyright (C) 1991-1996, Thomas G. Lane.
|
||||
* Modified 2019-2020 by Guido Vollbeding.
|
||||
* 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 routines to read input images in GIF format.
|
||||
*
|
||||
* These routines may need modification for non-Unix environments or
|
||||
* specialized applications. As they stand, they assume input from
|
||||
* an ordinary stdio stream. They further assume that reading begins
|
||||
* at the start of the file; start_input may need work if the
|
||||
* user interface has already read some data (e.g., to determine that
|
||||
* the file is indeed GIF format).
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is loosely based on giftoppm from the PBMPLUS distribution
|
||||
* of Feb. 1991. That file contains the following copyright notice:
|
||||
* +-------------------------------------------------------------------+
|
||||
* | Copyright 1990, David Koblas. |
|
||||
* | Permission to use, copy, modify, and distribute this software |
|
||||
* | and its documentation for any purpose and without fee is hereby |
|
||||
* | granted, provided that the above copyright notice appear in all |
|
||||
* | copies and that both that copyright notice and this permission |
|
||||
* | notice appear in supporting documentation. This software is |
|
||||
* | provided "as is" without express or implied warranty. |
|
||||
* +-------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
||||
|
||||
#ifdef GIF_SUPPORTED
|
||||
|
||||
|
||||
/* Macros to deal with unsigned chars as efficiently as compiler allows */
|
||||
|
||||
#ifdef HAVE_UNSIGNED_CHAR
|
||||
typedef unsigned char U_CHAR;
|
||||
#define UCH(x) ((int) (x))
|
||||
#else /* !HAVE_UNSIGNED_CHAR */
|
||||
typedef char U_CHAR;
|
||||
#ifdef CHAR_IS_UNSIGNED
|
||||
#define UCH(x) ((int) (x))
|
||||
#else
|
||||
#define UCH(x) ((int) (x) & 0xFF)
|
||||
#endif
|
||||
#endif /* HAVE_UNSIGNED_CHAR */
|
||||
|
||||
|
||||
#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
|
||||
|
||||
|
||||
#define MAXCOLORMAPSIZE 256 /* max # of colors in a GIF colormap */
|
||||
#define NUMCOLORS 3 /* # of colors */
|
||||
#define CM_RED 0 /* color component numbers */
|
||||
#define CM_GREEN 1
|
||||
#define CM_BLUE 2
|
||||
|
||||
#define MAX_LZW_BITS 12 /* maximum LZW code size */
|
||||
#define LZW_TABLE_SIZE (1<<MAX_LZW_BITS) /* # of possible LZW symbols */
|
||||
|
||||
/* Macros for extracting header data --- note we assume chars may be signed */
|
||||
|
||||
#define LM_to_uint(array, offset) ((unsigned int) UCH(array[offset]) + \
|
||||
(((unsigned int) UCH(array[offset+1])) << 8))
|
||||
|
||||
#define BitSet(byte, bit) ((byte) & (bit))
|
||||
#define INTERLACE 0x40 /* mask for bit signifying interlaced image */
|
||||
#define COLORMAPFLAG 0x80 /* mask for bit signifying colormap presence */
|
||||
|
||||
|
||||
/*
|
||||
* LZW decompression tables look like this:
|
||||
* symbol_head[K] = prefix symbol of any LZW symbol K (0..LZW_TABLE_SIZE-1)
|
||||
* symbol_tail[K] = suffix byte of any LZW symbol K (0..LZW_TABLE_SIZE-1)
|
||||
* Note that entries 0..end_code of the above tables are not used,
|
||||
* since those symbols represent raw bytes or special codes.
|
||||
*
|
||||
* The stack represents the not-yet-used expansion of the last LZW symbol.
|
||||
* In the worst case, a symbol could expand to as many bytes as there are
|
||||
* LZW symbols, so we allocate LZW_TABLE_SIZE bytes for the stack.
|
||||
* (This is conservative since that number includes the raw-byte symbols.)
|
||||
*
|
||||
* The tables are allocated from FAR heap space since they would use up
|
||||
* rather a lot of the near data space in a PC.
|
||||
*/
|
||||
|
||||
|
||||
/* Private version of data source object */
|
||||
|
||||
typedef struct {
|
||||
struct cjpeg_source_struct pub; /* public fields */
|
||||
|
||||
j_compress_ptr cinfo; /* back link saves passing separate parm */
|
||||
|
||||
JSAMPARRAY colormap; /* GIF colormap (converted to my format) */
|
||||
|
||||
/* State for GetCode and LZWReadByte */
|
||||
U_CHAR code_buf[256+4]; /* current input data block */
|
||||
int last_byte; /* # of bytes in code_buf */
|
||||
int last_bit; /* # of bits in code_buf */
|
||||
int cur_bit; /* next bit index to read */
|
||||
boolean first_time; /* flags first call to GetCode */
|
||||
boolean out_of_blocks; /* TRUE if hit terminator data block */
|
||||
|
||||
int input_code_size; /* codesize given in GIF file */
|
||||
int clear_code, end_code; /* values for Clear and End codes */
|
||||
|
||||
int code_size; /* current actual code size */
|
||||
int limit_code; /* 2^code_size */
|
||||
int max_code; /* first unused code value */
|
||||
|
||||
/* Private state for LZWReadByte */
|
||||
int oldcode; /* previous LZW symbol */
|
||||
int firstcode; /* first byte of oldcode's expansion */
|
||||
|
||||
/* LZW symbol table and expansion stack */
|
||||
UINT16 FAR *symbol_head; /* => table of prefix symbols */
|
||||
UINT8 FAR *symbol_tail; /* => table of suffix bytes */
|
||||
UINT8 FAR *symbol_stack; /* => stack for symbol expansions */
|
||||
UINT8 FAR *sp; /* stack pointer */
|
||||
|
||||
/* State for interlaced image processing */
|
||||
boolean is_interlaced; /* TRUE if have interlaced image */
|
||||
jvirt_sarray_ptr interlaced_image; /* full image in interlaced order */
|
||||
JDIMENSION cur_row_number; /* need to know actual row number */
|
||||
JDIMENSION pass2_offset; /* # of pixel rows in pass 1 */
|
||||
JDIMENSION pass3_offset; /* # of pixel rows in passes 1&2 */
|
||||
JDIMENSION pass4_offset; /* # of pixel rows in passes 1,2,3 */
|
||||
} gif_source_struct;
|
||||
|
||||
typedef gif_source_struct * gif_source_ptr;
|
||||
|
||||
|
||||
/* Forward declarations */
|
||||
METHODDEF(JDIMENSION) get_pixel_rows
|
||||
JPP((j_compress_ptr cinfo, cjpeg_source_ptr sinfo));
|
||||
METHODDEF(JDIMENSION) load_interlaced_image
|
||||
JPP((j_compress_ptr cinfo, cjpeg_source_ptr sinfo));
|
||||
METHODDEF(JDIMENSION) get_interlaced_row
|
||||
JPP((j_compress_ptr cinfo, cjpeg_source_ptr sinfo));
|
||||
|
||||
|
||||
LOCAL(int)
|
||||
ReadByte (gif_source_ptr sinfo)
|
||||
/* Read next byte from GIF file */
|
||||
{
|
||||
register FILE *infile = sinfo->pub.input_file;
|
||||
register int c;
|
||||
|
||||
if ((c = getc(infile)) == EOF)
|
||||
ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
LOCAL(int)
|
||||
GetDataBlock (gif_source_ptr sinfo, U_CHAR *buf)
|
||||
/* Read a GIF data block, which has a leading count byte */
|
||||
/* A zero-length block marks the end of a data block sequence */
|
||||
{
|
||||
int count;
|
||||
|
||||
count = ReadByte(sinfo);
|
||||
if (count > 0) {
|
||||
if (! ReadOK(sinfo->pub.input_file, buf, count))
|
||||
ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
SkipDataBlocks (gif_source_ptr sinfo)
|
||||
/* Skip a series of data blocks, until a block terminator is found */
|
||||
{
|
||||
U_CHAR buf[256];
|
||||
|
||||
while (GetDataBlock(sinfo, buf) > 0)
|
||||
/* skip */;
|
||||
}
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
ReInitLZW (gif_source_ptr sinfo)
|
||||
/* (Re)initialize LZW state; shared code for startup and Clear processing */
|
||||
{
|
||||
sinfo->code_size = sinfo->input_code_size + 1;
|
||||
sinfo->limit_code = sinfo->clear_code << 1; /* 2^code_size */
|
||||
sinfo->max_code = sinfo->clear_code + 2; /* first unused code value */
|
||||
sinfo->sp = sinfo->symbol_stack; /* init stack to empty */
|
||||
}
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
InitLZWCode (gif_source_ptr sinfo)
|
||||
/* Initialize for a series of LZWReadByte (and hence GetCode) calls */
|
||||
{
|
||||
/* GetCode initialization */
|
||||
sinfo->last_byte = 2; /* make safe to "recopy last two bytes" */
|
||||
sinfo->code_buf[0] = 0;
|
||||
sinfo->code_buf[1] = 0;
|
||||
sinfo->last_bit = 0; /* nothing in the buffer */
|
||||
sinfo->cur_bit = 0; /* force buffer load on first call */
|
||||
sinfo->first_time = TRUE;
|
||||
sinfo->out_of_blocks = FALSE;
|
||||
|
||||
/* LZWReadByte initialization: */
|
||||
/* compute special code values (note that these do not change later) */
|
||||
sinfo->clear_code = 1 << sinfo->input_code_size;
|
||||
sinfo->end_code = sinfo->clear_code + 1;
|
||||
ReInitLZW(sinfo);
|
||||
}
|
||||
|
||||
|
||||
LOCAL(int)
|
||||
GetCode (gif_source_ptr sinfo)
|
||||
/* Fetch the next code_size bits from the GIF data */
|
||||
/* We assume code_size is less than 16 */
|
||||
{
|
||||
register INT32 accum;
|
||||
int offs, count;
|
||||
|
||||
while (sinfo->cur_bit + sinfo->code_size > sinfo->last_bit) {
|
||||
/* Time to reload the buffer */
|
||||
/* First time, share code with Clear case */
|
||||
if (sinfo->first_time) {
|
||||
sinfo->first_time = FALSE;
|
||||
return sinfo->clear_code;
|
||||
}
|
||||
if (sinfo->out_of_blocks) {
|
||||
WARNMS(sinfo->cinfo, JWRN_GIF_NOMOREDATA);
|
||||
return sinfo->end_code; /* fake something useful */
|
||||
}
|
||||
/* preserve last two bytes of what we have -- assume code_size <= 16 */
|
||||
sinfo->code_buf[0] = sinfo->code_buf[sinfo->last_byte-2];
|
||||
sinfo->code_buf[1] = sinfo->code_buf[sinfo->last_byte-1];
|
||||
/* Load more bytes; set flag if we reach the terminator block */
|
||||
if ((count = GetDataBlock(sinfo, &sinfo->code_buf[2])) == 0) {
|
||||
sinfo->out_of_blocks = TRUE;
|
||||
WARNMS(sinfo->cinfo, JWRN_GIF_NOMOREDATA);
|
||||
return sinfo->end_code; /* fake something useful */
|
||||
}
|
||||
/* Reset counters */
|
||||
sinfo->cur_bit = (sinfo->cur_bit - sinfo->last_bit) + 16;
|
||||
sinfo->last_byte = 2 + count;
|
||||
sinfo->last_bit = sinfo->last_byte * 8;
|
||||
}
|
||||
|
||||
/* Form up next 24 bits in accum */
|
||||
offs = sinfo->cur_bit >> 3; /* byte containing cur_bit */
|
||||
accum = (INT32) UCH(sinfo->code_buf[offs+2]);
|
||||
accum <<= 8;
|
||||
accum |= (INT32) UCH(sinfo->code_buf[offs+1]);
|
||||
accum <<= 8;
|
||||
accum |= (INT32) UCH(sinfo->code_buf[offs]);
|
||||
|
||||
/* Right-align cur_bit in accum, then mask off desired number of bits */
|
||||
accum >>= (sinfo->cur_bit & 7);
|
||||
sinfo->cur_bit += sinfo->code_size;
|
||||
return ((int) accum) & ((1 << sinfo->code_size) - 1);
|
||||
}
|
||||
|
||||
|
||||
LOCAL(int)
|
||||
LZWReadByte (gif_source_ptr sinfo)
|
||||
/* Read an LZW-compressed byte */
|
||||
{
|
||||
register int code; /* current working code */
|
||||
int incode; /* saves actual input code */
|
||||
|
||||
/* If any codes are stacked from a previously read symbol, return them */
|
||||
if (sinfo->sp > sinfo->symbol_stack)
|
||||
return (int) *(-- sinfo->sp);
|
||||
|
||||
/* Time to read a new symbol */
|
||||
code = GetCode(sinfo);
|
||||
|
||||
if (code == sinfo->clear_code) {
|
||||
/* Reinit state, swallow any extra Clear codes, and */
|
||||
/* return next code, which is expected to be a raw byte. */
|
||||
ReInitLZW(sinfo);
|
||||
do {
|
||||
code = GetCode(sinfo);
|
||||
} while (code == sinfo->clear_code);
|
||||
if (code > sinfo->clear_code) { /* make sure it is a raw byte */
|
||||
WARNMS(sinfo->cinfo, JWRN_GIF_BADDATA);
|
||||
code = 0; /* use something valid */
|
||||
}
|
||||
/* make firstcode, oldcode valid! */
|
||||
sinfo->firstcode = sinfo->oldcode = code;
|
||||
return code;
|
||||
}
|
||||
|
||||
if (code == sinfo->end_code) {
|
||||
/* Skip the rest of the image, unless GetCode already read terminator */
|
||||
if (! sinfo->out_of_blocks) {
|
||||
SkipDataBlocks(sinfo);
|
||||
sinfo->out_of_blocks = TRUE;
|
||||
}
|
||||
/* Complain that there's not enough data */
|
||||
WARNMS(sinfo->cinfo, JWRN_GIF_ENDCODE);
|
||||
/* Pad data with 0's */
|
||||
return 0; /* fake something usable */
|
||||
}
|
||||
|
||||
/* Got normal raw byte or LZW symbol */
|
||||
incode = code; /* save for a moment */
|
||||
|
||||
if (code >= sinfo->max_code) { /* special case for not-yet-defined symbol */
|
||||
/* code == max_code is OK; anything bigger is bad data */
|
||||
if (code > sinfo->max_code) {
|
||||
WARNMS(sinfo->cinfo, JWRN_GIF_BADDATA);
|
||||
incode = 0; /* prevent creation of loops in symbol table */
|
||||
}
|
||||
/* this symbol will be defined as oldcode/firstcode */
|
||||
*(sinfo->sp++) = (UINT8) sinfo->firstcode;
|
||||
code = sinfo->oldcode;
|
||||
}
|
||||
|
||||
/* If it's a symbol, expand it into the stack */
|
||||
while (code >= sinfo->clear_code) {
|
||||
*(sinfo->sp++) = sinfo->symbol_tail[code]; /* tail is a byte value */
|
||||
code = sinfo->symbol_head[code]; /* head is another LZW symbol */
|
||||
}
|
||||
/* At this point code just represents a raw byte */
|
||||
sinfo->firstcode = code; /* save for possible future use */
|
||||
|
||||
/* If there's room in table... */
|
||||
if ((code = sinfo->max_code) < LZW_TABLE_SIZE) {
|
||||
/* Define a new symbol = prev sym + head of this sym's expansion */
|
||||
sinfo->symbol_head[code] = (UINT16) sinfo->oldcode;
|
||||
sinfo->symbol_tail[code] = (UINT8) sinfo->firstcode;
|
||||
sinfo->max_code++;
|
||||
/* Is it time to increase code_size? */
|
||||
if (sinfo->max_code >= sinfo->limit_code &&
|
||||
sinfo->code_size < MAX_LZW_BITS) {
|
||||
sinfo->code_size++;
|
||||
sinfo->limit_code <<= 1; /* keep equal to 2^code_size */
|
||||
}
|
||||
}
|
||||
|
||||
sinfo->oldcode = incode; /* save last input symbol for future use */
|
||||
return sinfo->firstcode; /* return first byte of symbol's expansion */
|
||||
}
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
ReadColorMap (gif_source_ptr sinfo, int cmaplen, JSAMPARRAY cmap)
|
||||
/* Read a GIF colormap */
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cmaplen; i++) {
|
||||
#if BITS_IN_JSAMPLE == 8
|
||||
#define UPSCALE(x) (x)
|
||||
#else
|
||||
#define UPSCALE(x) ((x) << (BITS_IN_JSAMPLE-8))
|
||||
#endif
|
||||
cmap[CM_RED ][i] = (JSAMPLE) UPSCALE(ReadByte(sinfo));
|
||||
cmap[CM_GREEN][i] = (JSAMPLE) UPSCALE(ReadByte(sinfo));
|
||||
cmap[CM_BLUE ][i] = (JSAMPLE) UPSCALE(ReadByte(sinfo));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
DoExtension (gif_source_ptr sinfo)
|
||||
/* Process an extension block */
|
||||
/* Currently we ignore 'em all */
|
||||
{
|
||||
int extlabel;
|
||||
|
||||
/* Read extension label byte */
|
||||
extlabel = ReadByte(sinfo);
|
||||
TRACEMS1(sinfo->cinfo, 1, JTRC_GIF_EXTENSION, extlabel);
|
||||
/* Skip the data block(s) associated with the extension */
|
||||
SkipDataBlocks(sinfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read the file header; return image size and component count.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
start_input_gif (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
{
|
||||
gif_source_ptr source = (gif_source_ptr) sinfo;
|
||||
U_CHAR hdrbuf[10]; /* workspace for reading control blocks */
|
||||
unsigned int width, height; /* image dimensions */
|
||||
int colormaplen, aspectRatio;
|
||||
int c;
|
||||
|
||||
/* Read and verify GIF Header */
|
||||
if (! ReadOK(source->pub.input_file, hdrbuf, 6))
|
||||
ERREXIT(cinfo, JERR_GIF_NOT);
|
||||
if (hdrbuf[0] != 'G' || hdrbuf[1] != 'I' || hdrbuf[2] != 'F')
|
||||
ERREXIT(cinfo, JERR_GIF_NOT);
|
||||
/* Check for expected version numbers.
|
||||
* If unknown version, give warning and try to process anyway;
|
||||
* this is per recommendation in GIF89a standard.
|
||||
*/
|
||||
if ((hdrbuf[3] != '8' || hdrbuf[4] != '7' || hdrbuf[5] != 'a') &&
|
||||
(hdrbuf[3] != '8' || hdrbuf[4] != '9' || hdrbuf[5] != 'a'))
|
||||
TRACEMS3(cinfo, 1, JTRC_GIF_BADVERSION, hdrbuf[3], hdrbuf[4], hdrbuf[5]);
|
||||
|
||||
/* Read and decipher Logical Screen Descriptor */
|
||||
if (! ReadOK(source->pub.input_file, hdrbuf, 7))
|
||||
ERREXIT(cinfo, JERR_INPUT_EOF);
|
||||
width = LM_to_uint(hdrbuf, 0);
|
||||
height = LM_to_uint(hdrbuf, 2);
|
||||
/* we ignore the color resolution, sort flag, and background color index */
|
||||
aspectRatio = UCH(hdrbuf[6]);
|
||||
if (aspectRatio != 0 && aspectRatio != 49)
|
||||
TRACEMS(cinfo, 1, JTRC_GIF_NONSQUARE);
|
||||
|
||||
/* Allocate space to store the colormap */
|
||||
source->colormap = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo,
|
||||
JPOOL_IMAGE, (JDIMENSION) MAXCOLORMAPSIZE, (JDIMENSION) NUMCOLORS);
|
||||
colormaplen = 0; /* indicate initialization */
|
||||
|
||||
/* Read global colormap if header indicates it is present */
|
||||
if (BitSet(hdrbuf[4], COLORMAPFLAG)) {
|
||||
colormaplen = 2 << (hdrbuf[4] & 0x07);
|
||||
ReadColorMap(source, colormaplen, source->colormap);
|
||||
}
|
||||
|
||||
/* Scan until we reach start of desired image.
|
||||
* We don't currently support skipping images, but could add it easily.
|
||||
*/
|
||||
for (;;) {
|
||||
c = ReadByte(source);
|
||||
|
||||
if (c == ';') /* GIF terminator?? */
|
||||
ERREXIT(cinfo, JERR_GIF_IMAGENOTFOUND);
|
||||
|
||||
if (c == '!') { /* Extension */
|
||||
DoExtension(source);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c != ',') { /* Not an image separator? */
|
||||
WARNMS1(cinfo, JWRN_GIF_CHAR, c);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Read and decipher Local Image Descriptor */
|
||||
if (! ReadOK(source->pub.input_file, hdrbuf, 9))
|
||||
ERREXIT(cinfo, JERR_INPUT_EOF);
|
||||
/* we ignore top/left position info, also sort flag */
|
||||
width = LM_to_uint(hdrbuf, 4);
|
||||
height = LM_to_uint(hdrbuf, 6);
|
||||
if (width <= 0 || height <= 0)
|
||||
ERREXIT(cinfo, JERR_GIF_OUTOFRANGE);
|
||||
source->is_interlaced = (BitSet(hdrbuf[8], INTERLACE) != 0);
|
||||
|
||||
/* Read local colormap if header indicates it is present */
|
||||
/* Note: if we wanted to support skipping images, */
|
||||
/* we'd need to skip rather than read colormap for ignored images */
|
||||
if (BitSet(hdrbuf[8], COLORMAPFLAG)) {
|
||||
colormaplen = 2 << (hdrbuf[8] & 0x07);
|
||||
ReadColorMap(source, colormaplen, source->colormap);
|
||||
}
|
||||
|
||||
source->input_code_size = ReadByte(source); /* get min-code-size byte */
|
||||
if (source->input_code_size < 2 || source->input_code_size > 8)
|
||||
ERREXIT1(cinfo, JERR_GIF_CODESIZE, source->input_code_size);
|
||||
|
||||
/* Reached desired image, so break out of loop */
|
||||
/* If we wanted to skip this image, */
|
||||
/* we'd call SkipDataBlocks and then continue the loop */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Prepare to read selected image: first initialize LZW decompressor */
|
||||
source->symbol_head = (UINT16 FAR *) (*cinfo->mem->alloc_large)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, LZW_TABLE_SIZE * SIZEOF(UINT16));
|
||||
source->symbol_tail = (UINT8 FAR *) (*cinfo->mem->alloc_large)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, LZW_TABLE_SIZE * SIZEOF(UINT8));
|
||||
source->symbol_stack = (UINT8 FAR *) (*cinfo->mem->alloc_large)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, LZW_TABLE_SIZE * SIZEOF(UINT8));
|
||||
InitLZWCode(source);
|
||||
|
||||
/*
|
||||
* If image is interlaced, we read it into a full-size sample array,
|
||||
* decompressing as we go; then get_interlaced_row selects rows from the
|
||||
* sample array in the proper order.
|
||||
*/
|
||||
if (source->is_interlaced) {
|
||||
/* We request the virtual array now, but can't access it until virtual
|
||||
* arrays have been allocated. Hence, the actual work of reading the
|
||||
* image is postponed until the first call to get_pixel_rows.
|
||||
*/
|
||||
source->interlaced_image = (*cinfo->mem->request_virt_sarray)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
|
||||
(JDIMENSION) width, (JDIMENSION) height, (JDIMENSION) 1);
|
||||
if (cinfo->progress != NULL) {
|
||||
cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
|
||||
progress->total_extra_passes++; /* count file input as separate pass */
|
||||
}
|
||||
source->pub.get_pixel_rows = load_interlaced_image;
|
||||
} else {
|
||||
source->pub.get_pixel_rows = get_pixel_rows;
|
||||
}
|
||||
|
||||
/* Create compressor input buffer. */
|
||||
source->pub.buffer = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo,
|
||||
JPOOL_IMAGE, (JDIMENSION) width * NUMCOLORS, (JDIMENSION) 1);
|
||||
source->pub.buffer_height = 1;
|
||||
|
||||
/* Pad colormap for safety. */
|
||||
for (c = colormaplen; c < source->clear_code; c++) {
|
||||
source->colormap[CM_RED ][c] =
|
||||
source->colormap[CM_GREEN][c] =
|
||||
source->colormap[CM_BLUE ][c] = CENTERJSAMPLE;
|
||||
}
|
||||
|
||||
/* Return info about the image. */
|
||||
cinfo->in_color_space = JCS_RGB;
|
||||
cinfo->input_components = NUMCOLORS;
|
||||
cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */
|
||||
cinfo->image_width = width;
|
||||
cinfo->image_height = height;
|
||||
|
||||
TRACEMS3(cinfo, 1, JTRC_GIF, width, height, colormaplen);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read one row of pixels.
|
||||
* This version is used for noninterlaced GIF images:
|
||||
* we read directly from the GIF file.
|
||||
*/
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
get_pixel_rows (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
{
|
||||
gif_source_ptr source = (gif_source_ptr) sinfo;
|
||||
register int c;
|
||||
register JSAMPROW ptr;
|
||||
register JDIMENSION col;
|
||||
register JSAMPARRAY colormap = source->colormap;
|
||||
|
||||
ptr = source->pub.buffer[0];
|
||||
for (col = cinfo->image_width; col > 0; col--) {
|
||||
c = LZWReadByte(source);
|
||||
*ptr++ = colormap[CM_RED ][c];
|
||||
*ptr++ = colormap[CM_GREEN][c];
|
||||
*ptr++ = colormap[CM_BLUE ][c];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read one row of pixels.
|
||||
* This version is used for the first call on get_pixel_rows when
|
||||
* reading an interlaced GIF file: we read the whole image into memory.
|
||||
*/
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
load_interlaced_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
{
|
||||
gif_source_ptr source = (gif_source_ptr) sinfo;
|
||||
register JSAMPROW sptr;
|
||||
register JDIMENSION col;
|
||||
JDIMENSION row;
|
||||
cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
|
||||
|
||||
/* Read the interlaced image into the virtual array we've created. */
|
||||
for (row = 0; row < cinfo->image_height; row++) {
|
||||
if (progress != NULL) {
|
||||
progress->pub.pass_counter = (long) row;
|
||||
progress->pub.pass_limit = (long) cinfo->image_height;
|
||||
(*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
|
||||
}
|
||||
sptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,
|
||||
source->interlaced_image, row, (JDIMENSION) 1, TRUE);
|
||||
for (col = cinfo->image_width; col > 0; col--) {
|
||||
*sptr++ = (JSAMPLE) LZWReadByte(source);
|
||||
}
|
||||
}
|
||||
if (progress != NULL)
|
||||
progress->completed_extra_passes++;
|
||||
|
||||
/* Replace method pointer so subsequent calls don't come here. */
|
||||
source->pub.get_pixel_rows = get_interlaced_row;
|
||||
/* Initialize for get_interlaced_row, and perform first call on it. */
|
||||
source->cur_row_number = 0;
|
||||
source->pass2_offset = (cinfo->image_height + 7) / 8;
|
||||
source->pass3_offset = source->pass2_offset + (cinfo->image_height + 3) / 8;
|
||||
source->pass4_offset = source->pass3_offset + (cinfo->image_height + 1) / 4;
|
||||
|
||||
return get_interlaced_row(cinfo, sinfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read one row of pixels.
|
||||
* This version is used for interlaced GIF images:
|
||||
* we read from the virtual array.
|
||||
*/
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
get_interlaced_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
{
|
||||
gif_source_ptr source = (gif_source_ptr) sinfo;
|
||||
register int c;
|
||||
register JSAMPROW sptr, ptr;
|
||||
register JDIMENSION col;
|
||||
register JSAMPARRAY colormap = source->colormap;
|
||||
JDIMENSION irow;
|
||||
|
||||
/* Figure out which row of interlaced image is needed, and access it. */
|
||||
switch ((int) (source->cur_row_number & 7)) {
|
||||
case 0: /* first-pass row */
|
||||
irow = source->cur_row_number >> 3;
|
||||
break;
|
||||
case 4: /* second-pass row */
|
||||
irow = (source->cur_row_number >> 3) + source->pass2_offset;
|
||||
break;
|
||||
case 2: /* third-pass row */
|
||||
case 6:
|
||||
irow = (source->cur_row_number >> 2) + source->pass3_offset;
|
||||
break;
|
||||
default: /* fourth-pass row */
|
||||
irow = (source->cur_row_number >> 1) + source->pass4_offset;
|
||||
}
|
||||
sptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,
|
||||
source->interlaced_image, irow, (JDIMENSION) 1, FALSE);
|
||||
/* Scan the row, expand colormap, and output */
|
||||
ptr = source->pub.buffer[0];
|
||||
for (col = cinfo->image_width; col > 0; col--) {
|
||||
c = GETJSAMPLE(*sptr++);
|
||||
*ptr++ = colormap[CM_RED ][c];
|
||||
*ptr++ = colormap[CM_GREEN][c];
|
||||
*ptr++ = colormap[CM_BLUE ][c];
|
||||
}
|
||||
source->cur_row_number++; /* for next time */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Finish up at the end of the file.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
finish_input_gif (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
{
|
||||
/* no work */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The module selection routine for GIF format input.
|
||||
*/
|
||||
|
||||
GLOBAL(cjpeg_source_ptr)
|
||||
jinit_read_gif (j_compress_ptr cinfo)
|
||||
{
|
||||
gif_source_ptr source;
|
||||
|
||||
/* Create module interface object */
|
||||
source = (gif_source_ptr) (*cinfo->mem->alloc_small)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(gif_source_struct));
|
||||
source->cinfo = cinfo; /* make back link for subroutines */
|
||||
/* Fill in method ptrs, except get_pixel_rows which start_input sets */
|
||||
source->pub.start_input = start_input_gif;
|
||||
source->pub.finish_input = finish_input_gif;
|
||||
|
||||
return &source->pub;
|
||||
}
|
||||
|
||||
#endif /* GIF_SUPPORTED */
|
||||
|
|
@ -1,515 +0,0 @@
|
|||
/*
|
||||
* rdjpgcom.c
|
||||
*
|
||||
* Copyright (C) 1994-1997, Thomas G. Lane.
|
||||
* Modified 2009 by Bill Allombert, Guido Vollbeding.
|
||||
* 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 a very simple stand-alone application that displays
|
||||
* the text in COM (comment) markers in a JFIF file.
|
||||
* This may be useful as an example of the minimum logic needed to parse
|
||||
* JPEG markers.
|
||||
*/
|
||||
|
||||
#define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */
|
||||
#include "jinclude.h" /* get auto-config symbols, <stdio.h> */
|
||||
|
||||
#ifdef HAVE_LOCALE_H
|
||||
#include <locale.h> /* Bill Allombert: use locale for isprint */
|
||||
#endif
|
||||
#include <ctype.h> /* to declare isupper(), tolower() */
|
||||
#ifdef USE_SETMODE
|
||||
#include <fcntl.h> /* to declare setmode()'s parameter macros */
|
||||
/* If you have setmode() but not <io.h>, just delete this line: */
|
||||
#include <io.h> /* to declare setmode() */
|
||||
#endif
|
||||
|
||||
#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
|
||||
#ifdef __MWERKS__
|
||||
#include <SIOUX.h> /* Metrowerks needs this */
|
||||
#include <console.h> /* ... and this */
|
||||
#endif
|
||||
#ifdef THINK_C
|
||||
#include <console.h> /* Think declares it here */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */
|
||||
#define READ_BINARY "r"
|
||||
#else
|
||||
#ifdef VMS /* VMS is very nonstandard */
|
||||
#define READ_BINARY "rb", "ctx=stm"
|
||||
#else /* standard ANSI-compliant case */
|
||||
#define READ_BINARY "rb"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef EXIT_FAILURE /* define exit() codes if not provided */
|
||||
#define EXIT_FAILURE 1
|
||||
#endif
|
||||
#ifndef EXIT_SUCCESS
|
||||
#ifdef VMS
|
||||
#define EXIT_SUCCESS 1 /* VMS is very nonstandard */
|
||||
#else
|
||||
#define EXIT_SUCCESS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* These macros are used to read the input file.
|
||||
* To reuse this code in another application, you might need to change these.
|
||||
*/
|
||||
|
||||
static FILE * infile; /* input JPEG file */
|
||||
|
||||
/* Return next input byte, or EOF if no more */
|
||||
#define NEXTBYTE() getc(infile)
|
||||
|
||||
|
||||
/* Error exit handler */
|
||||
#define ERREXIT(msg) (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE))
|
||||
|
||||
|
||||
/* Read one byte, testing for EOF */
|
||||
static int
|
||||
read_1_byte (void)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = NEXTBYTE();
|
||||
if (c == EOF)
|
||||
ERREXIT("Premature EOF in JPEG file");
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Read 2 bytes, convert to unsigned int */
|
||||
/* All 2-byte quantities in JPEG markers are MSB first */
|
||||
static unsigned int
|
||||
read_2_bytes (void)
|
||||
{
|
||||
int c1, c2;
|
||||
|
||||
c1 = NEXTBYTE();
|
||||
if (c1 == EOF)
|
||||
ERREXIT("Premature EOF in JPEG file");
|
||||
c2 = NEXTBYTE();
|
||||
if (c2 == EOF)
|
||||
ERREXIT("Premature EOF in JPEG file");
|
||||
return (((unsigned int) c1) << 8) + ((unsigned int) c2);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* JPEG markers consist of one or more 0xFF bytes, followed by a marker
|
||||
* code byte (which is not an FF). Here are the marker codes of interest
|
||||
* in this program. (See jdmarker.c for a more complete list.)
|
||||
*/
|
||||
|
||||
#define M_SOF0 0xC0 /* Start Of Frame N */
|
||||
#define M_SOF1 0xC1 /* N indicates which compression process */
|
||||
#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
|
||||
#define M_SOF3 0xC3
|
||||
#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
|
||||
#define M_SOF6 0xC6
|
||||
#define M_SOF7 0xC7
|
||||
#define M_SOF9 0xC9
|
||||
#define M_SOF10 0xCA
|
||||
#define M_SOF11 0xCB
|
||||
#define M_SOF13 0xCD
|
||||
#define M_SOF14 0xCE
|
||||
#define M_SOF15 0xCF
|
||||
#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */
|
||||
#define M_EOI 0xD9 /* End Of Image (end of datastream) */
|
||||
#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
|
||||
#define M_APP0 0xE0 /* Application-specific marker, type N */
|
||||
#define M_APP12 0xEC /* (we don't bother to list all 16 APPn's) */
|
||||
#define M_COM 0xFE /* COMment */
|
||||
|
||||
|
||||
/*
|
||||
* Find the next JPEG marker and return its marker code.
|
||||
* We expect at least one FF byte, possibly more if the compressor used FFs
|
||||
* to pad the file.
|
||||
* There could also be non-FF garbage between markers. The treatment of such
|
||||
* garbage is unspecified; we choose to skip over it but emit a warning msg.
|
||||
* NB: this routine must not be used after seeing SOS marker, since it will
|
||||
* not deal correctly with FF/00 sequences in the compressed image data...
|
||||
*/
|
||||
|
||||
static int
|
||||
next_marker (void)
|
||||
{
|
||||
int c;
|
||||
int discarded_bytes = 0;
|
||||
|
||||
/* Find 0xFF byte; count and skip any non-FFs. */
|
||||
c = read_1_byte();
|
||||
while (c != 0xFF) {
|
||||
discarded_bytes++;
|
||||
c = read_1_byte();
|
||||
}
|
||||
/* Get marker code byte, swallowing any duplicate FF bytes. Extra FFs
|
||||
* are legal as pad bytes, so don't count them in discarded_bytes.
|
||||
*/
|
||||
do {
|
||||
c = read_1_byte();
|
||||
} while (c == 0xFF);
|
||||
|
||||
if (discarded_bytes != 0) {
|
||||
fprintf(stderr, "Warning: garbage data found in JPEG file\n");
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read the initial marker, which should be SOI.
|
||||
* For a JFIF file, the first two bytes of the file should be literally
|
||||
* 0xFF M_SOI. To be more general, we could use next_marker, but if the
|
||||
* input file weren't actually JPEG at all, next_marker might read the whole
|
||||
* file and then return a misleading error message...
|
||||
*/
|
||||
|
||||
static int
|
||||
first_marker (void)
|
||||
{
|
||||
int c1, c2;
|
||||
|
||||
c1 = NEXTBYTE();
|
||||
c2 = NEXTBYTE();
|
||||
if (c1 != 0xFF || c2 != M_SOI)
|
||||
ERREXIT("Not a JPEG file");
|
||||
return c2;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Most types of marker are followed by a variable-length parameter segment.
|
||||
* This routine skips over the parameters for any marker we don't otherwise
|
||||
* want to process.
|
||||
* Note that we MUST skip the parameter segment explicitly in order not to
|
||||
* be fooled by 0xFF bytes that might appear within the parameter segment;
|
||||
* such bytes do NOT introduce new markers.
|
||||
*/
|
||||
|
||||
static void
|
||||
skip_variable (void)
|
||||
/* Skip over an unknown or uninteresting variable-length marker */
|
||||
{
|
||||
unsigned int length;
|
||||
|
||||
/* Get the marker parameter length count */
|
||||
length = read_2_bytes();
|
||||
/* Length includes itself, so must be at least 2 */
|
||||
if (length < 2)
|
||||
ERREXIT("Erroneous JPEG marker length");
|
||||
length -= 2;
|
||||
/* Skip over the remaining bytes */
|
||||
while (length > 0) {
|
||||
(void) read_1_byte();
|
||||
length--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Process a COM marker.
|
||||
* We want to print out the marker contents as legible text;
|
||||
* we must guard against non-text junk and varying newline representations.
|
||||
*/
|
||||
|
||||
static void
|
||||
process_COM (int raw)
|
||||
{
|
||||
unsigned int length;
|
||||
int ch;
|
||||
int lastch = 0;
|
||||
|
||||
/* Bill Allombert: set locale properly for isprint */
|
||||
#ifdef HAVE_LOCALE_H
|
||||
setlocale(LC_CTYPE, "");
|
||||
#endif
|
||||
|
||||
/* Get the marker parameter length count */
|
||||
length = read_2_bytes();
|
||||
/* Length includes itself, so must be at least 2 */
|
||||
if (length < 2)
|
||||
ERREXIT("Erroneous JPEG marker length");
|
||||
length -= 2;
|
||||
|
||||
while (length > 0) {
|
||||
ch = read_1_byte();
|
||||
if (raw) {
|
||||
putc(ch, stdout);
|
||||
/* Emit the character in a readable form.
|
||||
* Nonprintables are converted to \nnn form,
|
||||
* while \ is converted to \\.
|
||||
* Newlines in CR, CR/LF, or LF form will be printed as one newline.
|
||||
*/
|
||||
} else if (ch == '\r') {
|
||||
printf("\n");
|
||||
} else if (ch == '\n') {
|
||||
if (lastch != '\r')
|
||||
printf("\n");
|
||||
} else if (ch == '\\') {
|
||||
printf("\\\\");
|
||||
} else if (isprint(ch)) {
|
||||
putc(ch, stdout);
|
||||
} else {
|
||||
printf("\\%03o", ch);
|
||||
}
|
||||
lastch = ch;
|
||||
length--;
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/* Bill Allombert: revert to C locale */
|
||||
#ifdef HAVE_LOCALE_H
|
||||
setlocale(LC_CTYPE, "C");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Process a SOFn marker.
|
||||
* This code is only needed if you want to know the image dimensions...
|
||||
*/
|
||||
|
||||
static void
|
||||
process_SOFn (int marker)
|
||||
{
|
||||
unsigned int length;
|
||||
unsigned int image_height, image_width;
|
||||
int data_precision, num_components;
|
||||
const char * process;
|
||||
int ci;
|
||||
|
||||
length = read_2_bytes(); /* usual parameter length count */
|
||||
|
||||
data_precision = read_1_byte();
|
||||
image_height = read_2_bytes();
|
||||
image_width = read_2_bytes();
|
||||
num_components = read_1_byte();
|
||||
|
||||
switch (marker) {
|
||||
case M_SOF0: process = "Baseline"; break;
|
||||
case M_SOF1: process = "Extended sequential"; break;
|
||||
case M_SOF2: process = "Progressive"; break;
|
||||
case M_SOF3: process = "Lossless"; break;
|
||||
case M_SOF5: process = "Differential sequential"; break;
|
||||
case M_SOF6: process = "Differential progressive"; break;
|
||||
case M_SOF7: process = "Differential lossless"; break;
|
||||
case M_SOF9: process = "Extended sequential, arithmetic coding"; break;
|
||||
case M_SOF10: process = "Progressive, arithmetic coding"; break;
|
||||
case M_SOF11: process = "Lossless, arithmetic coding"; break;
|
||||
case M_SOF13: process = "Differential sequential, arithmetic coding"; break;
|
||||
case M_SOF14: process = "Differential progressive, arithmetic coding"; break;
|
||||
case M_SOF15: process = "Differential lossless, arithmetic coding"; break;
|
||||
default: process = "Unknown"; break;
|
||||
}
|
||||
|
||||
printf("JPEG image is %uw * %uh, %d color components, %d bits per sample\n",
|
||||
image_width, image_height, num_components, data_precision);
|
||||
printf("JPEG process: %s\n", process);
|
||||
|
||||
if (length != (unsigned int) (8 + num_components * 3))
|
||||
ERREXIT("Bogus SOF marker length");
|
||||
|
||||
for (ci = 0; ci < num_components; ci++) {
|
||||
(void) read_1_byte(); /* Component ID code */
|
||||
(void) read_1_byte(); /* H, V sampling factors */
|
||||
(void) read_1_byte(); /* Quantization table number */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse the marker stream until SOS or EOI is seen;
|
||||
* display any COM markers.
|
||||
* While the companion program wrjpgcom will always insert COM markers before
|
||||
* SOFn, other implementations might not, so we scan to SOS before stopping.
|
||||
* If we were only interested in the image dimensions, we would stop at SOFn.
|
||||
* (Conversely, if we only cared about COM markers, there would be no need
|
||||
* for special code to handle SOFn; we could treat it like other markers.)
|
||||
*/
|
||||
|
||||
static int
|
||||
scan_JPEG_header (int verbose, int raw)
|
||||
{
|
||||
int marker;
|
||||
|
||||
/* Expect SOI at start of file */
|
||||
if (first_marker() != M_SOI)
|
||||
ERREXIT("Expected SOI marker first");
|
||||
|
||||
/* Scan miscellaneous markers until we reach SOS. */
|
||||
for (;;) {
|
||||
marker = next_marker();
|
||||
switch (marker) {
|
||||
/* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be,
|
||||
* treated as SOFn. C4 in particular is actually DHT.
|
||||
*/
|
||||
case M_SOF0: /* Baseline */
|
||||
case M_SOF1: /* Extended sequential, Huffman */
|
||||
case M_SOF2: /* Progressive, Huffman */
|
||||
case M_SOF3: /* Lossless, Huffman */
|
||||
case M_SOF5: /* Differential sequential, Huffman */
|
||||
case M_SOF6: /* Differential progressive, Huffman */
|
||||
case M_SOF7: /* Differential lossless, Huffman */
|
||||
case M_SOF9: /* Extended sequential, arithmetic */
|
||||
case M_SOF10: /* Progressive, arithmetic */
|
||||
case M_SOF11: /* Lossless, arithmetic */
|
||||
case M_SOF13: /* Differential sequential, arithmetic */
|
||||
case M_SOF14: /* Differential progressive, arithmetic */
|
||||
case M_SOF15: /* Differential lossless, arithmetic */
|
||||
if (verbose)
|
||||
process_SOFn(marker);
|
||||
else
|
||||
skip_variable();
|
||||
break;
|
||||
|
||||
case M_SOS: /* stop before hitting compressed data */
|
||||
return marker;
|
||||
|
||||
case M_EOI: /* in case it's a tables-only JPEG stream */
|
||||
return marker;
|
||||
|
||||
case M_COM:
|
||||
process_COM(raw);
|
||||
break;
|
||||
|
||||
case M_APP12:
|
||||
/* Some digital camera makers put useful textual information into
|
||||
* APP12 markers, so we print those out too when in -verbose mode.
|
||||
*/
|
||||
if (verbose) {
|
||||
printf("APP12 contains:\n");
|
||||
process_COM(raw);
|
||||
} else
|
||||
skip_variable();
|
||||
break;
|
||||
|
||||
default: /* Anything else just gets skipped */
|
||||
skip_variable(); /* we assume it has a parameter count... */
|
||||
break;
|
||||
}
|
||||
} /* end loop */
|
||||
}
|
||||
|
||||
|
||||
/* Command line parsing code */
|
||||
|
||||
static const char * progname; /* program name for error messages */
|
||||
|
||||
|
||||
static void
|
||||
usage (void)
|
||||
/* complain about bad command line */
|
||||
{
|
||||
fprintf(stderr, "rdjpgcom displays any textual comments in a JPEG file.\n");
|
||||
|
||||
fprintf(stderr, "Usage: %s [switches] [inputfile]\n", progname);
|
||||
|
||||
fprintf(stderr, "Switches (names may be abbreviated):\n");
|
||||
fprintf(stderr, " -raw Display non-printable characters in comments (unsafe)\n");
|
||||
fprintf(stderr, " -verbose Also display dimensions of JPEG image\n");
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
keymatch (char * arg, const char * keyword, int minchars)
|
||||
/* Case-insensitive matching of (possibly abbreviated) keyword switches. */
|
||||
/* keyword is the constant keyword (must be lower case already), */
|
||||
/* minchars is length of minimum legal abbreviation. */
|
||||
{
|
||||
register int ca, ck;
|
||||
register int nmatched = 0;
|
||||
|
||||
while ((ca = *arg++) != '\0') {
|
||||
if ((ck = *keyword++) == '\0')
|
||||
return 0; /* arg longer than keyword, no good */
|
||||
if (isupper(ca)) /* force arg to lcase (assume ck is already) */
|
||||
ca = tolower(ca);
|
||||
if (ca != ck)
|
||||
return 0; /* no good */
|
||||
nmatched++; /* count matched characters */
|
||||
}
|
||||
/* reached end of argument; fail if it's too short for unique abbrev */
|
||||
if (nmatched < minchars)
|
||||
return 0;
|
||||
return 1; /* A-OK */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The main program.
|
||||
*/
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int argn;
|
||||
char * arg;
|
||||
int verbose = 0, raw = 0;
|
||||
|
||||
/* On Mac, fetch a command line. */
|
||||
#ifdef USE_CCOMMAND
|
||||
argc = ccommand(&argv);
|
||||
#endif
|
||||
|
||||
progname = argv[0];
|
||||
if (progname == NULL || progname[0] == 0)
|
||||
progname = "rdjpgcom"; /* in case C library doesn't provide it */
|
||||
|
||||
/* Parse switches, if any */
|
||||
for (argn = 1; argn < argc; argn++) {
|
||||
arg = argv[argn];
|
||||
if (arg[0] != '-')
|
||||
break; /* not switch, must be file name */
|
||||
arg++; /* advance over '-' */
|
||||
if (keymatch(arg, "verbose", 1)) {
|
||||
verbose++;
|
||||
} else if (keymatch(arg, "raw", 1)) {
|
||||
raw = 1;
|
||||
} else
|
||||
usage();
|
||||
}
|
||||
|
||||
/* Open the input file. */
|
||||
/* Unix style: expect zero or one file name */
|
||||
if (argn < argc-1) {
|
||||
fprintf(stderr, "%s: only one input file\n", progname);
|
||||
usage();
|
||||
}
|
||||
if (argn < argc) {
|
||||
if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) {
|
||||
fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
/* default input file is stdin */
|
||||
#ifdef USE_SETMODE /* need to hack file mode? */
|
||||
setmode(fileno(stdin), O_BINARY);
|
||||
#endif
|
||||
#ifdef USE_FDOPEN /* need to re-open in binary mode? */
|
||||
if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
|
||||
fprintf(stderr, "%s: can't open stdin\n", progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#else
|
||||
infile = stdin;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Scan the JPEG headers. */
|
||||
(void) scan_JPEG_header(verbose, raw);
|
||||
|
||||
/* All done. */
|
||||
exit(EXIT_SUCCESS);
|
||||
return 0; /* suppress no-return-value warnings */
|
||||
}
|
||||
|
|
@ -1,501 +0,0 @@
|
|||
/*
|
||||
* rdppm.c
|
||||
*
|
||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||
* Modified 2009-2020 by Bill Allombert, Guido Vollbeding.
|
||||
* 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 routines to read input images in PPM/PGM format.
|
||||
* The extended 2-byte-per-sample raw PPM/PGM formats are supported.
|
||||
* The PBMPLUS library is NOT required to compile this software
|
||||
* (but it is highly useful as a set of PPM image manipulation programs).
|
||||
*
|
||||
* These routines may need modification for non-Unix environments or
|
||||
* specialized applications. As they stand, they assume input from
|
||||
* an ordinary stdio stream. They further assume that reading begins
|
||||
* at the start of the file; start_input may need work if the
|
||||
* user interface has already read some data (e.g., to determine that
|
||||
* the file is indeed PPM format).
|
||||
*/
|
||||
|
||||
/* Portions of this code are based on the PBMPLUS library, which is:
|
||||
**
|
||||
** Copyright (C) 1988 by Jef Poskanzer.
|
||||
**
|
||||
** Permission to use, copy, modify, and distribute this software and its
|
||||
** documentation for any purpose and without fee is hereby granted, provided
|
||||
** that the above copyright notice appear in all copies and that both that
|
||||
** copyright notice and this permission notice appear in supporting
|
||||
** documentation. This software is provided "as is" without express or
|
||||
** implied warranty.
|
||||
*/
|
||||
|
||||
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
||||
|
||||
#ifdef PPM_SUPPORTED
|
||||
|
||||
|
||||
/* Macros to deal with unsigned chars as efficiently as compiler allows */
|
||||
|
||||
#ifdef HAVE_UNSIGNED_CHAR
|
||||
typedef unsigned char U_CHAR;
|
||||
#define UCH(x) ((int) (x))
|
||||
#else /* !HAVE_UNSIGNED_CHAR */
|
||||
typedef char U_CHAR;
|
||||
#ifdef CHAR_IS_UNSIGNED
|
||||
#define UCH(x) ((int) (x))
|
||||
#else
|
||||
#define UCH(x) ((int) (x) & 0xFF)
|
||||
#endif
|
||||
#endif /* HAVE_UNSIGNED_CHAR */
|
||||
|
||||
|
||||
#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
|
||||
|
||||
|
||||
/*
|
||||
* On most systems, reading individual bytes with getc() is drastically less
|
||||
* efficient than buffering a row at a time with fread(). On PCs, we must
|
||||
* allocate the buffer in near data space, because we are assuming small-data
|
||||
* memory model, wherein fread() can't reach far memory. If you need to
|
||||
* process very wide images on a PC, you might have to compile in large-memory
|
||||
* model, or else replace fread() with a getc() loop --- which will be much
|
||||
* slower.
|
||||
*/
|
||||
|
||||
|
||||
/* Private version of data source object */
|
||||
|
||||
typedef struct {
|
||||
struct cjpeg_source_struct pub; /* public fields */
|
||||
|
||||
/* Usually these two pointers point to the same place: */
|
||||
U_CHAR *iobuffer; /* fread's I/O buffer */
|
||||
JSAMPROW pixrow; /* compressor input buffer */
|
||||
size_t buffer_width; /* width of I/O buffer */
|
||||
JSAMPLE *rescale; /* => maxval-remapping array, or NULL */
|
||||
unsigned int maxval;
|
||||
} ppm_source_struct;
|
||||
|
||||
typedef ppm_source_struct * ppm_source_ptr;
|
||||
|
||||
|
||||
LOCAL(int)
|
||||
pbm_getc (FILE * infile)
|
||||
/* Read next char, skipping over any comments */
|
||||
/* A comment/newline sequence is returned as a newline */
|
||||
{
|
||||
register int ch;
|
||||
|
||||
ch = getc(infile);
|
||||
if (ch == '#') {
|
||||
do {
|
||||
ch = getc(infile);
|
||||
} while (ch != '\n' && ch != EOF);
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
|
||||
LOCAL(unsigned int)
|
||||
read_pbm_integer (j_compress_ptr cinfo, FILE * infile)
|
||||
/* Read an unsigned decimal integer from the PPM file */
|
||||
/* Swallows one trailing character after the integer */
|
||||
/* Note that on a 16-bit-int machine, only values up to 64k can be read. */
|
||||
/* This should not be a problem in practice. */
|
||||
{
|
||||
register int ch;
|
||||
register unsigned int val;
|
||||
|
||||
/* Skip any leading whitespace */
|
||||
do {
|
||||
ch = pbm_getc(infile);
|
||||
if (ch == EOF)
|
||||
ERREXIT(cinfo, JERR_INPUT_EOF);
|
||||
} while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
|
||||
|
||||
if (ch < '0' || ch > '9')
|
||||
ERREXIT(cinfo, JERR_PPM_NONNUMERIC);
|
||||
|
||||
val = ch - '0';
|
||||
while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') {
|
||||
val *= 10;
|
||||
val += ch - '0';
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read one row of pixels.
|
||||
*
|
||||
* We provide several different versions depending on input file format.
|
||||
* In all cases, input is scaled to the size of JSAMPLE.
|
||||
*
|
||||
* A really fast path is provided for reading byte/sample raw files with
|
||||
* maxval = MAXJSAMPLE, which is the normal case for 8-bit data.
|
||||
*/
|
||||
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
get_text_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
/* This version is for reading text-format PGM files with any maxval */
|
||||
{
|
||||
ppm_source_ptr source = (ppm_source_ptr) sinfo;
|
||||
FILE * infile = source->pub.input_file;
|
||||
register JSAMPROW ptr;
|
||||
register JSAMPLE *rescale = source->rescale;
|
||||
unsigned int maxval = source->maxval;
|
||||
JDIMENSION col;
|
||||
|
||||
ptr = source->pixrow;
|
||||
for (col = cinfo->image_width; col > 0; col--) {
|
||||
register unsigned int temp;
|
||||
temp = read_pbm_integer(cinfo, infile);
|
||||
if (temp > maxval)
|
||||
ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
|
||||
*ptr++ = rescale[temp];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
get_text_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
/* This version is for reading text-format PPM files with any maxval */
|
||||
{
|
||||
ppm_source_ptr source = (ppm_source_ptr) sinfo;
|
||||
FILE * infile = source->pub.input_file;
|
||||
register JSAMPROW ptr;
|
||||
register JSAMPLE *rescale = source->rescale;
|
||||
unsigned int maxval = source->maxval;
|
||||
JDIMENSION col;
|
||||
|
||||
ptr = source->pixrow;
|
||||
for (col = cinfo->image_width; col > 0; col--) {
|
||||
register unsigned int temp;
|
||||
temp = read_pbm_integer(cinfo, infile);
|
||||
if (temp > maxval)
|
||||
ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
|
||||
*ptr++ = rescale[temp];
|
||||
temp = read_pbm_integer(cinfo, infile);
|
||||
if (temp > maxval)
|
||||
ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
|
||||
*ptr++ = rescale[temp];
|
||||
temp = read_pbm_integer(cinfo, infile);
|
||||
if (temp > maxval)
|
||||
ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
|
||||
*ptr++ = rescale[temp];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
get_scaled_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
/* This version is for reading raw-byte-format PGM files with any maxval */
|
||||
{
|
||||
ppm_source_ptr source = (ppm_source_ptr) sinfo;
|
||||
register JSAMPROW ptr;
|
||||
register U_CHAR * bufferptr;
|
||||
register JSAMPLE *rescale = source->rescale;
|
||||
unsigned int maxval = source->maxval;
|
||||
JDIMENSION col;
|
||||
|
||||
if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
|
||||
ERREXIT(cinfo, JERR_INPUT_EOF);
|
||||
ptr = source->pixrow;
|
||||
bufferptr = source->iobuffer;
|
||||
for (col = cinfo->image_width; col > 0; col--) {
|
||||
register unsigned int temp;
|
||||
temp = (unsigned int) UCH(*bufferptr++);
|
||||
if (temp > maxval)
|
||||
ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
|
||||
*ptr++ = rescale[temp];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
get_scaled_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
/* This version is for reading raw-byte-format PPM files with any maxval */
|
||||
{
|
||||
ppm_source_ptr source = (ppm_source_ptr) sinfo;
|
||||
register JSAMPROW ptr;
|
||||
register U_CHAR * bufferptr;
|
||||
register JSAMPLE *rescale = source->rescale;
|
||||
unsigned int maxval = source->maxval;
|
||||
JDIMENSION col;
|
||||
|
||||
if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
|
||||
ERREXIT(cinfo, JERR_INPUT_EOF);
|
||||
ptr = source->pixrow;
|
||||
bufferptr = source->iobuffer;
|
||||
for (col = cinfo->image_width; col > 0; col--) {
|
||||
register unsigned int temp;
|
||||
temp = (unsigned int) UCH(*bufferptr++);
|
||||
if (temp > maxval)
|
||||
ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
|
||||
*ptr++ = rescale[temp];
|
||||
temp = (unsigned int) UCH(*bufferptr++);
|
||||
if (temp > maxval)
|
||||
ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
|
||||
*ptr++ = rescale[temp];
|
||||
temp = (unsigned int) UCH(*bufferptr++);
|
||||
if (temp > maxval)
|
||||
ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
|
||||
*ptr++ = rescale[temp];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
get_raw_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
/* This version is for reading raw-byte-format files with maxval = MAXJSAMPLE.
|
||||
* In this case we just read right into the JSAMPLE buffer!
|
||||
* Note that same code works for PPM and PGM files.
|
||||
*/
|
||||
{
|
||||
ppm_source_ptr source = (ppm_source_ptr) sinfo;
|
||||
|
||||
if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
|
||||
ERREXIT(cinfo, JERR_INPUT_EOF);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
get_word_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
/* This version is for reading raw-word-format PGM files with any maxval */
|
||||
{
|
||||
ppm_source_ptr source = (ppm_source_ptr) sinfo;
|
||||
register JSAMPROW ptr;
|
||||
register U_CHAR * bufferptr;
|
||||
register JSAMPLE *rescale = source->rescale;
|
||||
unsigned int maxval = source->maxval;
|
||||
JDIMENSION col;
|
||||
|
||||
if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
|
||||
ERREXIT(cinfo, JERR_INPUT_EOF);
|
||||
ptr = source->pixrow;
|
||||
bufferptr = source->iobuffer;
|
||||
for (col = cinfo->image_width; col > 0; col--) {
|
||||
register unsigned int temp;
|
||||
temp = ((unsigned int) UCH(*bufferptr++)) << 8;
|
||||
temp |= (unsigned int) UCH(*bufferptr++);
|
||||
if (temp > maxval)
|
||||
ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
|
||||
*ptr++ = rescale[temp];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
get_word_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
/* This version is for reading raw-word-format PPM files with any maxval */
|
||||
{
|
||||
ppm_source_ptr source = (ppm_source_ptr) sinfo;
|
||||
register JSAMPROW ptr;
|
||||
register U_CHAR * bufferptr;
|
||||
register JSAMPLE *rescale = source->rescale;
|
||||
unsigned int maxval = source->maxval;
|
||||
JDIMENSION col;
|
||||
|
||||
if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
|
||||
ERREXIT(cinfo, JERR_INPUT_EOF);
|
||||
ptr = source->pixrow;
|
||||
bufferptr = source->iobuffer;
|
||||
for (col = cinfo->image_width; col > 0; col--) {
|
||||
register unsigned int temp;
|
||||
temp = ((unsigned int) UCH(*bufferptr++)) << 8;
|
||||
temp |= (unsigned int) UCH(*bufferptr++);
|
||||
if (temp > maxval)
|
||||
ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
|
||||
*ptr++ = rescale[temp];
|
||||
temp = ((unsigned int) UCH(*bufferptr++)) << 8;
|
||||
temp |= (unsigned int) UCH(*bufferptr++);
|
||||
if (temp > maxval)
|
||||
ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
|
||||
*ptr++ = rescale[temp];
|
||||
temp = ((unsigned int) UCH(*bufferptr++)) << 8;
|
||||
temp |= (unsigned int) UCH(*bufferptr++);
|
||||
if (temp > maxval)
|
||||
ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
|
||||
*ptr++ = rescale[temp];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read the file header; return image size and component count.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
start_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
{
|
||||
ppm_source_ptr source = (ppm_source_ptr) sinfo;
|
||||
int c;
|
||||
unsigned int w, h, maxval;
|
||||
boolean need_iobuffer, use_raw_buffer, need_rescale;
|
||||
|
||||
if (getc(source->pub.input_file) != 'P')
|
||||
ERREXIT(cinfo, JERR_PPM_NOT);
|
||||
|
||||
c = getc(source->pub.input_file); /* subformat discriminator character */
|
||||
|
||||
/* detect unsupported variants (ie, PBM) before trying to read header */
|
||||
switch (c) {
|
||||
case '2': /* it's a text-format PGM file */
|
||||
case '3': /* it's a text-format PPM file */
|
||||
case '5': /* it's a raw-format PGM file */
|
||||
case '6': /* it's a raw-format PPM file */
|
||||
break;
|
||||
default:
|
||||
ERREXIT(cinfo, JERR_PPM_NOT);
|
||||
}
|
||||
|
||||
/* fetch the remaining header info */
|
||||
w = read_pbm_integer(cinfo, source->pub.input_file);
|
||||
h = read_pbm_integer(cinfo, source->pub.input_file);
|
||||
maxval = read_pbm_integer(cinfo, source->pub.input_file);
|
||||
|
||||
if (w <= 0 || h <= 0 || maxval <= 0) /* error check */
|
||||
ERREXIT(cinfo, JERR_PPM_NOT);
|
||||
|
||||
if (((long) w >> 24) || /* sanity check for buffer allocation below */
|
||||
((long) maxval >> 16)) /* support max 16-bit (2-byte) sample values */
|
||||
ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
|
||||
|
||||
cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */
|
||||
cinfo->image_width = (JDIMENSION) w;
|
||||
cinfo->image_height = (JDIMENSION) h;
|
||||
source->maxval = maxval;
|
||||
|
||||
/* initialize flags to most common settings */
|
||||
need_iobuffer = TRUE; /* do we need an I/O buffer? */
|
||||
use_raw_buffer = FALSE; /* do we map input buffer onto I/O buffer? */
|
||||
need_rescale = TRUE; /* do we need a rescale array? */
|
||||
|
||||
switch (c) {
|
||||
case '2': /* it's a text-format PGM file */
|
||||
cinfo->input_components = 1;
|
||||
cinfo->in_color_space = JCS_GRAYSCALE;
|
||||
TRACEMS2(cinfo, 1, JTRC_PGM_TEXT, w, h);
|
||||
source->pub.get_pixel_rows = get_text_gray_row;
|
||||
need_iobuffer = FALSE;
|
||||
break;
|
||||
|
||||
case '3': /* it's a text-format PPM file */
|
||||
cinfo->input_components = 3;
|
||||
cinfo->in_color_space = JCS_RGB;
|
||||
TRACEMS2(cinfo, 1, JTRC_PPM_TEXT, w, h);
|
||||
source->pub.get_pixel_rows = get_text_rgb_row;
|
||||
need_iobuffer = FALSE;
|
||||
break;
|
||||
|
||||
case '5': /* it's a raw-format PGM file */
|
||||
cinfo->input_components = 1;
|
||||
cinfo->in_color_space = JCS_GRAYSCALE;
|
||||
TRACEMS2(cinfo, 1, JTRC_PGM, w, h);
|
||||
if (maxval > 255) {
|
||||
source->pub.get_pixel_rows = get_word_gray_row;
|
||||
} else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) {
|
||||
source->pub.get_pixel_rows = get_raw_row;
|
||||
use_raw_buffer = TRUE;
|
||||
need_rescale = FALSE;
|
||||
} else {
|
||||
source->pub.get_pixel_rows = get_scaled_gray_row;
|
||||
}
|
||||
break;
|
||||
|
||||
case '6': /* it's a raw-format PPM file */
|
||||
cinfo->input_components = 3;
|
||||
cinfo->in_color_space = JCS_RGB;
|
||||
TRACEMS2(cinfo, 1, JTRC_PPM, w, h);
|
||||
if (maxval > 255) {
|
||||
source->pub.get_pixel_rows = get_word_rgb_row;
|
||||
} else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) {
|
||||
source->pub.get_pixel_rows = get_raw_row;
|
||||
use_raw_buffer = TRUE;
|
||||
need_rescale = FALSE;
|
||||
} else {
|
||||
source->pub.get_pixel_rows = get_scaled_rgb_row;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Allocate space for I/O buffer: 1 or 3 bytes or words/pixel. */
|
||||
if (need_iobuffer) {
|
||||
source->buffer_width = (size_t) w * (size_t) cinfo->input_components *
|
||||
((maxval <= 255) ? SIZEOF(U_CHAR) : (2 * SIZEOF(U_CHAR)));
|
||||
source->iobuffer = (U_CHAR *) (*cinfo->mem->alloc_small)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, source->buffer_width);
|
||||
}
|
||||
|
||||
/* Create compressor input buffer. */
|
||||
if (use_raw_buffer) {
|
||||
/* For unscaled raw-input case, we can just map it onto the I/O buffer. */
|
||||
/* Cast here implies near->far pointer conversion on PCs */
|
||||
source->pixrow = (JSAMPROW) source->iobuffer;
|
||||
} else {
|
||||
/* Need to translate anyway, so make a separate sample buffer. */
|
||||
source->pixrow = (JSAMPROW) (*cinfo->mem->alloc_large)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, (size_t) w *
|
||||
(size_t) cinfo->input_components * SIZEOF(JSAMPLE));
|
||||
}
|
||||
/* Synthesize a JSAMPARRAY pointer structure */
|
||||
source->pub.buffer = & source->pixrow;
|
||||
source->pub.buffer_height = 1;
|
||||
|
||||
/* Compute the rescaling array if required. */
|
||||
if (need_rescale) {
|
||||
INT32 val, half_maxval;
|
||||
|
||||
/* On 16-bit-int machines we have to be careful of maxval = 65535 */
|
||||
source->rescale = (JSAMPLE *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,
|
||||
JPOOL_IMAGE, ((size_t) maxval + (size_t) 1) * SIZEOF(JSAMPLE));
|
||||
half_maxval = maxval / 2;
|
||||
for (val = 0; val <= (INT32) maxval; val++) {
|
||||
/* The multiplication here must be done in 32 bits to avoid overflow */
|
||||
source->rescale[val] = (JSAMPLE) ((val * MAXJSAMPLE + half_maxval) / maxval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Finish up at the end of the file.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
finish_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
{
|
||||
/* no work */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The module selection routine for PPM format input.
|
||||
*/
|
||||
|
||||
GLOBAL(cjpeg_source_ptr)
|
||||
jinit_read_ppm (j_compress_ptr cinfo)
|
||||
{
|
||||
ppm_source_ptr source;
|
||||
|
||||
/* Create module interface object */
|
||||
source = (ppm_source_ptr) (*cinfo->mem->alloc_small)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(ppm_source_struct));
|
||||
/* Fill in method ptrs, except get_pixel_rows which start_input sets */
|
||||
source->pub.start_input = start_input_ppm;
|
||||
source->pub.finish_input = finish_input_ppm;
|
||||
|
||||
return &source->pub;
|
||||
}
|
||||
|
||||
#endif /* PPM_SUPPORTED */
|
||||
|
|
@ -1,380 +0,0 @@
|
|||
/*
|
||||
* rdrle.c
|
||||
*
|
||||
* Copyright (C) 1991-1996, Thomas G. Lane.
|
||||
* Modified 2019 by Guido Vollbeding.
|
||||
* 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 routines to read input images in Utah RLE format.
|
||||
* The Utah Raster Toolkit library is required (version 3.1 or later).
|
||||
*
|
||||
* These routines may need modification for non-Unix environments or
|
||||
* specialized applications. As they stand, they assume input from
|
||||
* an ordinary stdio stream. They further assume that reading begins
|
||||
* at the start of the file; start_input may need work if the
|
||||
* user interface has already read some data (e.g., to determine that
|
||||
* the file is indeed RLE format).
|
||||
*
|
||||
* Based on code contributed by Mike Lijewski,
|
||||
* with updates from Robert Hutchinson.
|
||||
*/
|
||||
|
||||
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
||||
|
||||
#ifdef RLE_SUPPORTED
|
||||
|
||||
/* rle.h is provided by the Utah Raster Toolkit. */
|
||||
|
||||
#include <rle.h>
|
||||
|
||||
/*
|
||||
* We assume that JSAMPLE has the same representation as rle_pixel,
|
||||
* to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples.
|
||||
*/
|
||||
|
||||
#if BITS_IN_JSAMPLE != 8
|
||||
Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We support the following types of RLE files:
|
||||
*
|
||||
* GRAYSCALE - 8 bits, no colormap
|
||||
* MAPPEDGRAY - 8 bits, 1 channel colomap
|
||||
* PSEUDOCOLOR - 8 bits, 3 channel colormap
|
||||
* TRUECOLOR - 24 bits, 3 channel colormap
|
||||
* DIRECTCOLOR - 24 bits, no colormap
|
||||
*
|
||||
* For now, we ignore any alpha channel in the image.
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{ GRAYSCALE, MAPPEDGRAY, PSEUDOCOLOR, TRUECOLOR, DIRECTCOLOR } rle_kind;
|
||||
|
||||
|
||||
/*
|
||||
* Since RLE stores scanlines bottom-to-top, we have to invert the image
|
||||
* to conform to JPEG's top-to-bottom order. To do this, we read the
|
||||
* incoming image into a virtual array on the first get_pixel_rows call,
|
||||
* then fetch the required row from the virtual array on subsequent calls.
|
||||
*/
|
||||
|
||||
typedef struct _rle_source_struct * rle_source_ptr;
|
||||
|
||||
typedef struct _rle_source_struct {
|
||||
struct cjpeg_source_struct pub; /* public fields */
|
||||
|
||||
rle_kind visual; /* actual type of input file */
|
||||
jvirt_sarray_ptr image; /* virtual array to hold the image */
|
||||
JDIMENSION row; /* current row # in the virtual array */
|
||||
rle_hdr header; /* Input file information */
|
||||
rle_pixel **rle_row; /* holds a row returned by rle_getrow() */
|
||||
|
||||
} rle_source_struct;
|
||||
|
||||
|
||||
/*
|
||||
* Read the file header; return image size and component count.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
start_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
{
|
||||
rle_source_ptr source = (rle_source_ptr) sinfo;
|
||||
JDIMENSION width, height;
|
||||
#ifdef PROGRESS_REPORT
|
||||
cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
|
||||
#endif
|
||||
|
||||
/* Use RLE library routine to get the header info */
|
||||
source->header = *rle_hdr_init(NULL);
|
||||
source->header.rle_file = source->pub.input_file;
|
||||
switch (rle_get_setup(&(source->header))) {
|
||||
case RLE_SUCCESS:
|
||||
/* A-OK */
|
||||
break;
|
||||
case RLE_NOT_RLE:
|
||||
ERREXIT(cinfo, JERR_RLE_NOT);
|
||||
case RLE_NO_SPACE:
|
||||
ERREXIT(cinfo, JERR_RLE_MEM);
|
||||
case RLE_EMPTY:
|
||||
ERREXIT(cinfo, JERR_RLE_EMPTY);
|
||||
case RLE_EOF:
|
||||
ERREXIT(cinfo, JERR_RLE_EOF);
|
||||
default:
|
||||
ERREXIT(cinfo, JERR_RLE_BADERROR);
|
||||
}
|
||||
|
||||
/* Figure out what we have, set private vars and return values accordingly */
|
||||
|
||||
width = source->header.xmax - source->header.xmin + 1;
|
||||
height = source->header.ymax - source->header.ymin + 1;
|
||||
source->header.xmin = 0; /* realign horizontally */
|
||||
source->header.xmax = width-1;
|
||||
|
||||
cinfo->image_width = width;
|
||||
cinfo->image_height = height;
|
||||
cinfo->data_precision = 8; /* we can only handle 8 bit data */
|
||||
|
||||
if (source->header.ncolors == 1 && source->header.ncmap == 0) {
|
||||
source->visual = GRAYSCALE;
|
||||
TRACEMS2(cinfo, 1, JTRC_RLE_GRAY, width, height);
|
||||
} else if (source->header.ncolors == 1 && source->header.ncmap == 1) {
|
||||
source->visual = MAPPEDGRAY;
|
||||
TRACEMS3(cinfo, 1, JTRC_RLE_MAPGRAY, width, height,
|
||||
1 << source->header.cmaplen);
|
||||
} else if (source->header.ncolors == 1 && source->header.ncmap == 3) {
|
||||
source->visual = PSEUDOCOLOR;
|
||||
TRACEMS3(cinfo, 1, JTRC_RLE_MAPPED, width, height,
|
||||
1 << source->header.cmaplen);
|
||||
} else if (source->header.ncolors == 3 && source->header.ncmap == 3) {
|
||||
source->visual = TRUECOLOR;
|
||||
TRACEMS3(cinfo, 1, JTRC_RLE_FULLMAP, width, height,
|
||||
1 << source->header.cmaplen);
|
||||
} else if (source->header.ncolors == 3 && source->header.ncmap == 0) {
|
||||
source->visual = DIRECTCOLOR;
|
||||
TRACEMS2(cinfo, 1, JTRC_RLE, width, height);
|
||||
} else
|
||||
ERREXIT(cinfo, JERR_RLE_UNSUPPORTED);
|
||||
|
||||
if (source->visual == GRAYSCALE || source->visual == MAPPEDGRAY) {
|
||||
cinfo->in_color_space = JCS_GRAYSCALE;
|
||||
cinfo->input_components = 1;
|
||||
} else {
|
||||
cinfo->in_color_space = JCS_RGB;
|
||||
cinfo->input_components = 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* A place to hold each scanline while it's converted.
|
||||
* (GRAYSCALE scanlines don't need converting)
|
||||
*/
|
||||
if (source->visual != GRAYSCALE) {
|
||||
source->rle_row = (rle_pixel **) (*cinfo->mem->alloc_sarray)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE,
|
||||
width, (JDIMENSION) cinfo->input_components);
|
||||
}
|
||||
|
||||
/* request a virtual array to hold the image */
|
||||
source->image = (*cinfo->mem->request_virt_sarray)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
|
||||
width * (JDIMENSION) source->header.ncolors, height, (JDIMENSION) 1);
|
||||
|
||||
#ifdef PROGRESS_REPORT
|
||||
if (progress != NULL) {
|
||||
/* count file input as separate pass */
|
||||
progress->total_extra_passes++;
|
||||
}
|
||||
#endif
|
||||
|
||||
source->pub.buffer_height = 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read one row of pixels.
|
||||
* Called only after load_image has read the image into the virtual array.
|
||||
* Used for GRAYSCALE, MAPPEDGRAY, TRUECOLOR, and DIRECTCOLOR images.
|
||||
*/
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
get_rle_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
{
|
||||
rle_source_ptr source = (rle_source_ptr) sinfo;
|
||||
|
||||
source->row--;
|
||||
source->pub.buffer = (*cinfo->mem->access_virt_sarray)
|
||||
((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read one row of pixels.
|
||||
* Called only after load_image has read the image into the virtual array.
|
||||
* Used for PSEUDOCOLOR images.
|
||||
*/
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
get_pseudocolor_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
{
|
||||
rle_source_ptr source = (rle_source_ptr) sinfo;
|
||||
JSAMPROW src_row, dest_row;
|
||||
JDIMENSION col;
|
||||
rle_map *colormap;
|
||||
int val;
|
||||
|
||||
colormap = source->header.cmap;
|
||||
dest_row = source->pub.buffer[0];
|
||||
source->row--;
|
||||
src_row = * (*cinfo->mem->access_virt_sarray)
|
||||
((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);
|
||||
|
||||
for (col = cinfo->image_width; col > 0; col--) {
|
||||
val = GETJSAMPLE(*src_row++);
|
||||
*dest_row++ = (JSAMPLE) (colormap[val ] >> 8);
|
||||
*dest_row++ = (JSAMPLE) (colormap[val + 256] >> 8);
|
||||
*dest_row++ = (JSAMPLE) (colormap[val + 512] >> 8);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Load the image into a virtual array. We have to do this because RLE
|
||||
* files start at the lower left while the JPEG standard has them starting
|
||||
* in the upper left. This is called the first time we want to get a row
|
||||
* of input. What we do is load the RLE data into the array and then call
|
||||
* the appropriate routine to read one row from the array. Before returning,
|
||||
* we set source->pub.get_pixel_rows so that subsequent calls go straight to
|
||||
* the appropriate row-reading routine.
|
||||
*/
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
load_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
{
|
||||
rle_source_ptr source = (rle_source_ptr) sinfo;
|
||||
JDIMENSION row, col;
|
||||
JSAMPROW scanline, red_ptr, green_ptr, blue_ptr;
|
||||
rle_pixel **rle_row;
|
||||
rle_map *colormap;
|
||||
char channel;
|
||||
#ifdef PROGRESS_REPORT
|
||||
cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
|
||||
#endif
|
||||
|
||||
/* Read the RLE data into our virtual array.
|
||||
* We assume here that (a) rle_pixel is represented the same as JSAMPLE,
|
||||
* and (b) we are not on a machine where FAR pointers differ from regular.
|
||||
*/
|
||||
RLE_CLR_BIT(source->header, RLE_ALPHA); /* don't read the alpha channel */
|
||||
|
||||
#ifdef PROGRESS_REPORT
|
||||
if (progress != NULL) {
|
||||
progress->pub.pass_limit = cinfo->image_height;
|
||||
progress->pub.pass_counter = 0;
|
||||
(*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (source->visual) {
|
||||
|
||||
case GRAYSCALE:
|
||||
case PSEUDOCOLOR:
|
||||
for (row = 0; row < cinfo->image_height; row++) {
|
||||
rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray)
|
||||
((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
|
||||
rle_getrow(&source->header, rle_row);
|
||||
#ifdef PROGRESS_REPORT
|
||||
if (progress != NULL) {
|
||||
progress->pub.pass_counter++;
|
||||
(*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case MAPPEDGRAY:
|
||||
case TRUECOLOR:
|
||||
rle_row = source->rle_row;
|
||||
colormap = source->header.cmap;
|
||||
for (row = 0; row < cinfo->image_height; row++) {
|
||||
rle_getrow(&source->header, rle_row);
|
||||
scanline = * (*cinfo->mem->access_virt_sarray)
|
||||
((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
|
||||
|
||||
for (col = 0; col < cinfo->image_width; col++) {
|
||||
for (channel = 0; channel < source->header.ncolors; channel++) {
|
||||
*scanline++ = (JSAMPLE)
|
||||
(colormap[GETJSAMPLE(rle_row[channel][col]) + 256 * channel] >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PROGRESS_REPORT
|
||||
if (progress != NULL) {
|
||||
progress->pub.pass_counter++;
|
||||
(*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case DIRECTCOLOR:
|
||||
rle_row = source->rle_row;
|
||||
for (row = 0; row < cinfo->image_height; row++) {
|
||||
rle_getrow(&source->header, rle_row);
|
||||
scanline = * (*cinfo->mem->access_virt_sarray)
|
||||
((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
|
||||
|
||||
red_ptr = rle_row[0];
|
||||
green_ptr = rle_row[1];
|
||||
blue_ptr = rle_row[2];
|
||||
|
||||
for (col = cinfo->image_width; col > 0; col--) {
|
||||
*scanline++ = *red_ptr++;
|
||||
*scanline++ = *green_ptr++;
|
||||
*scanline++ = *blue_ptr++;
|
||||
}
|
||||
|
||||
#ifdef PROGRESS_REPORT
|
||||
if (progress != NULL) {
|
||||
progress->pub.pass_counter++;
|
||||
(*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PROGRESS_REPORT
|
||||
if (progress != NULL)
|
||||
progress->completed_extra_passes++;
|
||||
#endif
|
||||
|
||||
/* Set up to call proper row-extraction routine in future */
|
||||
if (source->visual == PSEUDOCOLOR) {
|
||||
source->pub.buffer = source->rle_row;
|
||||
source->pub.get_pixel_rows = get_pseudocolor_row;
|
||||
} else {
|
||||
source->pub.get_pixel_rows = get_rle_row;
|
||||
}
|
||||
source->row = cinfo->image_height;
|
||||
|
||||
/* And fetch the topmost (bottommost) row */
|
||||
return (*source->pub.get_pixel_rows) (cinfo, sinfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Finish up at the end of the file.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
finish_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
{
|
||||
/* no work */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The module selection routine for RLE format input.
|
||||
*/
|
||||
|
||||
GLOBAL(cjpeg_source_ptr)
|
||||
jinit_read_rle (j_compress_ptr cinfo)
|
||||
{
|
||||
rle_source_ptr source;
|
||||
|
||||
/* Create module interface object */
|
||||
source = (rle_source_ptr) (*cinfo->mem->alloc_small)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(rle_source_struct));
|
||||
/* Fill in method ptrs */
|
||||
source->pub.start_input = start_input_rle;
|
||||
source->pub.finish_input = finish_input_rle;
|
||||
source->pub.get_pixel_rows = load_image;
|
||||
|
||||
return &source->pub;
|
||||
}
|
||||
|
||||
#endif /* RLE_SUPPORTED */
|
||||
|
|
@ -1,363 +0,0 @@
|
|||
/*
|
||||
* rdswitch.c
|
||||
*
|
||||
* Copyright (C) 1991-1996, Thomas G. Lane.
|
||||
* Modified 2003-2020 by Guido Vollbeding.
|
||||
* 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 routines to process some of cjpeg's more complicated
|
||||
* command-line switches. Switches processed here are:
|
||||
* -qtables file Read quantization tables from text file
|
||||
* -scans file Read scan script from text file
|
||||
* -quality N[,N,...] Set quality ratings
|
||||
* -qslots N[,N,...] Set component quantization table selectors
|
||||
* -sample HxV[,HxV,...] Set component sampling factors
|
||||
*/
|
||||
|
||||
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
||||
#include <ctype.h> /* to declare isdigit(), isspace() */
|
||||
|
||||
|
||||
LOCAL(int)
|
||||
text_getc (FILE * file)
|
||||
/* Read next char, skipping over any comments (# to end of line) */
|
||||
/* A comment/newline sequence is returned as a newline */
|
||||
{
|
||||
register int ch;
|
||||
|
||||
ch = getc(file);
|
||||
if (ch == '#') {
|
||||
do {
|
||||
ch = getc(file);
|
||||
} while (ch != '\n' && ch != EOF);
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
|
||||
LOCAL(boolean)
|
||||
read_text_integer (FILE * file, long * result, int * termchar)
|
||||
/* Read an unsigned decimal integer from a file, store it in result */
|
||||
/* Reads one trailing character after the integer; returns it in termchar */
|
||||
{
|
||||
register int ch;
|
||||
register long val;
|
||||
|
||||
/* Skip any leading whitespace, detect EOF */
|
||||
do {
|
||||
ch = text_getc(file);
|
||||
if (ch == EOF) {
|
||||
*termchar = ch;
|
||||
return FALSE;
|
||||
}
|
||||
} while (isspace(ch));
|
||||
|
||||
if (! isdigit(ch)) {
|
||||
*termchar = ch;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
val = ch - '0';
|
||||
while ((ch = text_getc(file)) != EOF) {
|
||||
if (! isdigit(ch))
|
||||
break;
|
||||
val *= 10;
|
||||
val += ch - '0';
|
||||
}
|
||||
*result = val;
|
||||
*termchar = ch;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
GLOBAL(boolean)
|
||||
read_quant_tables (j_compress_ptr cinfo, char * filename, boolean force_baseline)
|
||||
/* Read a set of quantization tables from the specified file.
|
||||
* The file is plain ASCII text: decimal numbers with whitespace between.
|
||||
* Comments preceded by '#' may be included in the file.
|
||||
* There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values.
|
||||
* The tables are implicitly numbered 0,1,etc.
|
||||
* NOTE: does not affect the qslots mapping, which will default to selecting
|
||||
* table 0 for luminance (or primary) components, 1 for chrominance components.
|
||||
* You must use -qslots if you want a different component->table mapping.
|
||||
*/
|
||||
{
|
||||
FILE * fp;
|
||||
int tblno, i, termchar;
|
||||
long val;
|
||||
unsigned int table[DCTSIZE2];
|
||||
|
||||
if ((fp = fopen(filename, "r")) == NULL) {
|
||||
fprintf(stderr, "Can't open table file %s\n", filename);
|
||||
return FALSE;
|
||||
}
|
||||
tblno = 0;
|
||||
|
||||
while (read_text_integer(fp, &val, &termchar)) { /* read 1st element of table */
|
||||
if (tblno >= NUM_QUANT_TBLS) {
|
||||
fprintf(stderr, "Too many tables in file %s\n", filename);
|
||||
fclose(fp);
|
||||
return FALSE;
|
||||
}
|
||||
table[0] = (unsigned int) val;
|
||||
for (i = 1; i < DCTSIZE2; i++) {
|
||||
if (! read_text_integer(fp, &val, &termchar)) {
|
||||
fprintf(stderr, "Invalid table data in file %s\n", filename);
|
||||
fclose(fp);
|
||||
return FALSE;
|
||||
}
|
||||
table[i] = (unsigned int) val;
|
||||
}
|
||||
jpeg_add_quant_table(cinfo, tblno, table, cinfo->q_scale_factor[tblno],
|
||||
force_baseline);
|
||||
tblno++;
|
||||
}
|
||||
|
||||
if (termchar != EOF) {
|
||||
fprintf(stderr, "Non-numeric data in file %s\n", filename);
|
||||
fclose(fp);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
#ifdef C_MULTISCAN_FILES_SUPPORTED
|
||||
|
||||
LOCAL(boolean)
|
||||
read_scan_integer (FILE * file, long * result, int * termchar)
|
||||
/* Variant of read_text_integer that always looks for a non-space termchar;
|
||||
* this simplifies parsing of punctuation in scan scripts.
|
||||
*/
|
||||
{
|
||||
register int ch;
|
||||
|
||||
if (! read_text_integer(file, result, termchar))
|
||||
return FALSE;
|
||||
ch = *termchar;
|
||||
while (ch != EOF && isspace(ch))
|
||||
ch = text_getc(file);
|
||||
if (isdigit(ch)) { /* oops, put it back */
|
||||
if (ungetc(ch, file) == EOF)
|
||||
return FALSE;
|
||||
ch = ' ';
|
||||
} else {
|
||||
/* Any separators other than ';' and ':' are ignored;
|
||||
* this allows user to insert commas, etc, if desired.
|
||||
*/
|
||||
if (ch != EOF && ch != ';' && ch != ':')
|
||||
ch = ' ';
|
||||
}
|
||||
*termchar = ch;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
GLOBAL(boolean)
|
||||
read_scan_script (j_compress_ptr cinfo, char * filename)
|
||||
/* Read a scan script from the specified text file.
|
||||
* Each entry in the file defines one scan to be emitted.
|
||||
* Entries are separated by semicolons ';'.
|
||||
* An entry contains one to four component indexes,
|
||||
* optionally followed by a colon ':' and four progressive-JPEG parameters.
|
||||
* The component indexes denote which component(s) are to be transmitted
|
||||
* in the current scan. The first component has index 0.
|
||||
* Sequential JPEG is used if the progressive-JPEG parameters are omitted.
|
||||
* The file is free format text: any whitespace may appear between numbers
|
||||
* and the ':' and ';' punctuation marks. Also, other punctuation (such
|
||||
* as commas or dashes) can be placed between numbers if desired.
|
||||
* Comments preceded by '#' may be included in the file.
|
||||
* Note: we do very little validity checking here;
|
||||
* jcmaster.c will validate the script parameters.
|
||||
*/
|
||||
{
|
||||
FILE * fp;
|
||||
int scanno, ncomps, termchar;
|
||||
long val;
|
||||
jpeg_scan_info * scanptr;
|
||||
#define MAX_SCANS 100 /* quite arbitrary limit */
|
||||
jpeg_scan_info scans[MAX_SCANS];
|
||||
|
||||
if ((fp = fopen(filename, "r")) == NULL) {
|
||||
fprintf(stderr, "Can't open scan definition file %s\n", filename);
|
||||
return FALSE;
|
||||
}
|
||||
scanptr = scans;
|
||||
scanno = 0;
|
||||
|
||||
while (read_scan_integer(fp, &val, &termchar)) {
|
||||
if (scanno >= MAX_SCANS) {
|
||||
fprintf(stderr, "Too many scans defined in file %s\n", filename);
|
||||
fclose(fp);
|
||||
return FALSE;
|
||||
}
|
||||
scanptr->component_index[0] = (int) val;
|
||||
ncomps = 1;
|
||||
while (termchar == ' ') {
|
||||
if (ncomps >= MAX_COMPS_IN_SCAN) {
|
||||
fprintf(stderr, "Too many components in one scan in file %s\n",
|
||||
filename);
|
||||
fclose(fp);
|
||||
return FALSE;
|
||||
}
|
||||
if (! read_scan_integer(fp, &val, &termchar))
|
||||
goto bogus;
|
||||
scanptr->component_index[ncomps] = (int) val;
|
||||
ncomps++;
|
||||
}
|
||||
scanptr->comps_in_scan = ncomps;
|
||||
if (termchar == ':') {
|
||||
if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
|
||||
goto bogus;
|
||||
scanptr->Ss = (int) val;
|
||||
if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
|
||||
goto bogus;
|
||||
scanptr->Se = (int) val;
|
||||
if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
|
||||
goto bogus;
|
||||
scanptr->Ah = (int) val;
|
||||
if (! read_scan_integer(fp, &val, &termchar))
|
||||
goto bogus;
|
||||
scanptr->Al = (int) val;
|
||||
} else {
|
||||
/* set non-progressive parameters */
|
||||
scanptr->Ss = 0;
|
||||
scanptr->Se = DCTSIZE2-1;
|
||||
scanptr->Ah = 0;
|
||||
scanptr->Al = 0;
|
||||
}
|
||||
if (termchar != ';' && termchar != EOF) {
|
||||
bogus:
|
||||
fprintf(stderr, "Invalid scan entry format in file %s\n", filename);
|
||||
fclose(fp);
|
||||
return FALSE;
|
||||
}
|
||||
scanptr++, scanno++;
|
||||
}
|
||||
|
||||
if (termchar != EOF) {
|
||||
fprintf(stderr, "Non-numeric data in file %s\n", filename);
|
||||
fclose(fp);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (scanno > 0) {
|
||||
/* Stash completed scan list in cinfo structure.
|
||||
* NOTE: for cjpeg's use, JPOOL_IMAGE is the right lifetime for this data,
|
||||
* but if you want to compress multiple images you'd want JPOOL_PERMANENT.
|
||||
*/
|
||||
scanptr = (jpeg_scan_info *) (*cinfo->mem->alloc_small)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, scanno * SIZEOF(jpeg_scan_info));
|
||||
MEMCOPY(scanptr, scans, scanno * SIZEOF(jpeg_scan_info));
|
||||
cinfo->scan_info = scanptr;
|
||||
cinfo->num_scans = scanno;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif /* C_MULTISCAN_FILES_SUPPORTED */
|
||||
|
||||
|
||||
GLOBAL(boolean)
|
||||
set_quality_ratings (j_compress_ptr cinfo, char *arg, boolean force_baseline)
|
||||
/* Process a quality-ratings parameter string, of the form
|
||||
* N[,N,...]
|
||||
* If there are more q-table slots than parameters, the last value is replicated.
|
||||
*/
|
||||
{
|
||||
int val = 75; /* default value */
|
||||
int tblno;
|
||||
char ch;
|
||||
|
||||
for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
|
||||
if (*arg) {
|
||||
ch = ','; /* if not set by sscanf, will be ',' */
|
||||
if (sscanf(arg, "%d%c", &val, &ch) < 1)
|
||||
return FALSE;
|
||||
if (ch != ',') /* syntax check */
|
||||
return FALSE;
|
||||
/* Convert user 0-100 rating to percentage scaling */
|
||||
cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
|
||||
while (*arg && *arg++ != ','); /* advance to next segment of arg string */
|
||||
} else {
|
||||
/* reached end of parameter, set remaining factors to last value */
|
||||
cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
|
||||
}
|
||||
}
|
||||
jpeg_default_qtables(cinfo, force_baseline);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
GLOBAL(boolean)
|
||||
set_quant_slots (j_compress_ptr cinfo, char *arg)
|
||||
/* Process a quantization-table-selectors parameter string, of the form
|
||||
* N[,N,...]
|
||||
* If there are more components than parameters, the last value is replicated.
|
||||
*/
|
||||
{
|
||||
int val = 0; /* default table # */
|
||||
int ci;
|
||||
char ch;
|
||||
|
||||
for (ci = 0; ci < MAX_COMPONENTS; ci++) {
|
||||
if (*arg) {
|
||||
ch = ','; /* if not set by sscanf, will be ',' */
|
||||
if (sscanf(arg, "%d%c", &val, &ch) < 1)
|
||||
return FALSE;
|
||||
if (ch != ',') /* syntax check */
|
||||
return FALSE;
|
||||
if (val < 0 || val >= NUM_QUANT_TBLS) {
|
||||
fprintf(stderr, "JPEG quantization tables are numbered 0..%d\n",
|
||||
NUM_QUANT_TBLS-1);
|
||||
return FALSE;
|
||||
}
|
||||
cinfo->comp_info[ci].quant_tbl_no = val;
|
||||
while (*arg && *arg++ != ','); /* advance to next segment of arg string */
|
||||
} else {
|
||||
/* reached end of parameter, set remaining components to last table */
|
||||
cinfo->comp_info[ci].quant_tbl_no = val;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
GLOBAL(boolean)
|
||||
set_sample_factors (j_compress_ptr cinfo, char *arg)
|
||||
/* Process a sample-factors parameter string, of the form
|
||||
* HxV[,HxV,...]
|
||||
* If there are more components than parameters, "1x1" is assumed for the rest.
|
||||
*/
|
||||
{
|
||||
int ci, val1, val2;
|
||||
char ch1, ch2;
|
||||
|
||||
for (ci = 0; ci < MAX_COMPONENTS; ci++) {
|
||||
if (*arg) {
|
||||
ch2 = ','; /* if not set by sscanf, will be ',' */
|
||||
if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3)
|
||||
return FALSE;
|
||||
if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */
|
||||
return FALSE;
|
||||
if (val1 <= 0 || val1 > MAX_SAMP_FACTOR ||
|
||||
val2 <= 0 || val2 > MAX_SAMP_FACTOR) {
|
||||
fprintf(stderr, "JPEG sampling factors must be 1..%d\n", MAX_SAMP_FACTOR);
|
||||
return FALSE;
|
||||
}
|
||||
cinfo->comp_info[ci].h_samp_factor = val1;
|
||||
cinfo->comp_info[ci].v_samp_factor = val2;
|
||||
while (*arg && *arg++ != ','); /* advance to next segment of arg string */
|
||||
} else {
|
||||
/* reached end of parameter, set remaining components to 1x1 sampling */
|
||||
cinfo->comp_info[ci].h_samp_factor = 1;
|
||||
cinfo->comp_info[ci].v_samp_factor = 1;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -1,500 +0,0 @@
|
|||
/*
|
||||
* rdtarga.c
|
||||
*
|
||||
* Copyright (C) 1991-1996, Thomas G. Lane.
|
||||
* Modified 2017-2019 by Guido Vollbeding.
|
||||
* 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 routines to read input images in Targa format.
|
||||
*
|
||||
* These routines may need modification for non-Unix environments or
|
||||
* specialized applications. As they stand, they assume input from
|
||||
* an ordinary stdio stream. They further assume that reading begins
|
||||
* at the start of the file; start_input may need work if the
|
||||
* user interface has already read some data (e.g., to determine that
|
||||
* the file is indeed Targa format).
|
||||
*
|
||||
* Based on code contributed by Lee Daniel Crocker.
|
||||
*/
|
||||
|
||||
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
||||
|
||||
#ifdef TARGA_SUPPORTED
|
||||
|
||||
|
||||
/* Macros to deal with unsigned chars as efficiently as compiler allows */
|
||||
|
||||
#ifdef HAVE_UNSIGNED_CHAR
|
||||
typedef unsigned char U_CHAR;
|
||||
#define UCH(x) ((int) (x))
|
||||
#else /* !HAVE_UNSIGNED_CHAR */
|
||||
typedef char U_CHAR;
|
||||
#ifdef CHAR_IS_UNSIGNED
|
||||
#define UCH(x) ((int) (x))
|
||||
#else
|
||||
#define UCH(x) ((int) (x) & 0xFF)
|
||||
#endif
|
||||
#endif /* HAVE_UNSIGNED_CHAR */
|
||||
|
||||
|
||||
#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
|
||||
|
||||
|
||||
/* Private version of data source object */
|
||||
|
||||
typedef struct _tga_source_struct * tga_source_ptr;
|
||||
|
||||
typedef struct _tga_source_struct {
|
||||
struct cjpeg_source_struct pub; /* public fields */
|
||||
|
||||
j_compress_ptr cinfo; /* back link saves passing separate parm */
|
||||
|
||||
JSAMPARRAY colormap; /* Targa colormap (converted to my format) */
|
||||
|
||||
jvirt_sarray_ptr whole_image; /* Needed if funny input row order */
|
||||
JDIMENSION current_row; /* Current logical row number to read */
|
||||
|
||||
/* Pointer to routine to extract next Targa pixel from input file */
|
||||
JMETHOD(void, read_pixel, (tga_source_ptr sinfo));
|
||||
|
||||
/* Result of read_pixel is delivered here: */
|
||||
U_CHAR tga_pixel[4];
|
||||
|
||||
int pixel_size; /* Bytes per Targa pixel (1 to 4) */
|
||||
int cmap_length; /* colormap length */
|
||||
|
||||
/* State info for reading RLE-coded pixels; both counts must be init to 0 */
|
||||
int block_count; /* # of pixels remaining in RLE block */
|
||||
int dup_pixel_count; /* # of times to duplicate previous pixel */
|
||||
|
||||
/* This saves the correct pixel-row-expansion method for preload_image */
|
||||
JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo,
|
||||
cjpeg_source_ptr sinfo));
|
||||
} tga_source_struct;
|
||||
|
||||
|
||||
/* For expanding 5-bit pixel values to 8-bit with best rounding */
|
||||
|
||||
static const UINT8 c5to8bits[32] = {
|
||||
0, 8, 16, 25, 33, 41, 49, 58,
|
||||
66, 74, 82, 90, 99, 107, 115, 123,
|
||||
132, 140, 148, 156, 165, 173, 181, 189,
|
||||
197, 206, 214, 222, 230, 239, 247, 255
|
||||
};
|
||||
|
||||
|
||||
|
||||
LOCAL(int)
|
||||
read_byte (tga_source_ptr sinfo)
|
||||
/* Read next byte from Targa file */
|
||||
{
|
||||
register FILE *infile = sinfo->pub.input_file;
|
||||
register int c;
|
||||
|
||||
if ((c = getc(infile)) == EOF)
|
||||
ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
read_colormap (tga_source_ptr sinfo, int cmaplen, int mapentrysize)
|
||||
/* Read the colormap from a Targa file */
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Presently only handles 24-bit BGR format */
|
||||
if (mapentrysize != 24)
|
||||
ERREXIT(sinfo->cinfo, JERR_TGA_BADCMAP);
|
||||
|
||||
for (i = 0; i < cmaplen; i++) {
|
||||
sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo);
|
||||
sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo);
|
||||
sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* read_pixel methods: get a single pixel from Targa file into tga_pixel[]
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
read_non_rle_pixel (tga_source_ptr sinfo)
|
||||
/* Read one Targa pixel from the input file; no RLE expansion */
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < sinfo->pixel_size; i++) {
|
||||
sinfo->tga_pixel[i] = (U_CHAR) read_byte(sinfo);
|
||||
}
|
||||
}
|
||||
|
||||
METHODDEF(void)
|
||||
read_rle_pixel (tga_source_ptr sinfo)
|
||||
/* Read one Targa pixel from the input file, expanding RLE data as needed */
|
||||
{
|
||||
register int i;
|
||||
|
||||
/* Duplicate previously read pixel? */
|
||||
if (sinfo->dup_pixel_count > 0) {
|
||||
sinfo->dup_pixel_count--;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Time to read RLE block header? */
|
||||
if (--sinfo->block_count < 0) { /* decrement pixels remaining in block */
|
||||
i = read_byte(sinfo);
|
||||
if (i & 0x80) { /* Start of duplicate-pixel block? */
|
||||
sinfo->dup_pixel_count = i & 0x7F; /* number of dups after this one */
|
||||
sinfo->block_count = 0; /* then read new block header */
|
||||
} else {
|
||||
sinfo->block_count = i & 0x7F; /* number of pixels after this one */
|
||||
}
|
||||
}
|
||||
|
||||
/* Read next pixel */
|
||||
for (i = 0; i < sinfo->pixel_size; i++) {
|
||||
sinfo->tga_pixel[i] = (U_CHAR) read_byte(sinfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read one row of pixels.
|
||||
*
|
||||
* We provide several different versions depending on input file format.
|
||||
*/
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
get_8bit_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
/* This version is for reading 8-bit grayscale pixels */
|
||||
{
|
||||
tga_source_ptr source = (tga_source_ptr) sinfo;
|
||||
register JSAMPROW ptr;
|
||||
register JDIMENSION col;
|
||||
|
||||
ptr = source->pub.buffer[0];
|
||||
for (col = cinfo->image_width; col > 0; col--) {
|
||||
(*source->read_pixel) (source); /* Load next pixel into tga_pixel */
|
||||
*ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
get_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
/* This version is for reading 8-bit colormap indexes */
|
||||
{
|
||||
tga_source_ptr source = (tga_source_ptr) sinfo;
|
||||
register JSAMPROW ptr;
|
||||
register JSAMPARRAY colormap;
|
||||
register JDIMENSION col;
|
||||
register int t;
|
||||
int cmaplen;
|
||||
|
||||
ptr = source->pub.buffer[0];
|
||||
colormap = source->colormap;
|
||||
cmaplen = source->cmap_length;
|
||||
for (col = cinfo->image_width; col > 0; col--) {
|
||||
(*source->read_pixel) (source); /* Load next pixel into tga_pixel */
|
||||
t = UCH(source->tga_pixel[0]);
|
||||
if (t >= cmaplen)
|
||||
ERREXIT(cinfo, JERR_TGA_BADPARMS);
|
||||
*ptr++ = colormap[0][t];
|
||||
*ptr++ = colormap[1][t];
|
||||
*ptr++ = colormap[2][t];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
get_16bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
/* This version is for reading 16-bit pixels */
|
||||
{
|
||||
tga_source_ptr source = (tga_source_ptr) sinfo;
|
||||
register int t;
|
||||
register JSAMPROW ptr;
|
||||
register JDIMENSION col;
|
||||
|
||||
ptr = source->pub.buffer[0];
|
||||
for (col = cinfo->image_width; col > 0; col--) {
|
||||
(*source->read_pixel) (source); /* Load next pixel into tga_pixel */
|
||||
t = UCH(source->tga_pixel[0]);
|
||||
t += UCH(source->tga_pixel[1]) << 8;
|
||||
/* We expand 5 bit data to 8 bit sample width.
|
||||
* The format of the 16-bit (LSB first) input word is
|
||||
* xRRRRRGGGGGBBBBB
|
||||
*/
|
||||
ptr[2] = (JSAMPLE) c5to8bits[t & 0x1F];
|
||||
t >>= 5;
|
||||
ptr[1] = (JSAMPLE) c5to8bits[t & 0x1F];
|
||||
t >>= 5;
|
||||
ptr[0] = (JSAMPLE) c5to8bits[t & 0x1F];
|
||||
ptr += 3;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
/* This version is for reading 24-bit pixels */
|
||||
{
|
||||
tga_source_ptr source = (tga_source_ptr) sinfo;
|
||||
register JSAMPROW ptr;
|
||||
register JDIMENSION col;
|
||||
|
||||
ptr = source->pub.buffer[0];
|
||||
for (col = cinfo->image_width; col > 0; col--) {
|
||||
(*source->read_pixel) (source); /* Load next pixel into tga_pixel */
|
||||
*ptr++ = (JSAMPLE) UCH(source->tga_pixel[2]); /* change BGR to RGB order */
|
||||
*ptr++ = (JSAMPLE) UCH(source->tga_pixel[1]);
|
||||
*ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Targa also defines a 32-bit pixel format with order B,G,R,A.
|
||||
* We presently ignore the attribute byte, so the code for reading
|
||||
* these pixels is identical to the 24-bit routine above.
|
||||
* This works because the actual pixel length is only known to read_pixel.
|
||||
*/
|
||||
|
||||
#define get_32bit_row get_24bit_row
|
||||
|
||||
|
||||
/*
|
||||
* This method is for re-reading the input data in standard top-down
|
||||
* row order. The entire image has already been read into whole_image
|
||||
* with proper conversion of pixel format, but it's in a funny row order.
|
||||
*/
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
get_memory_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
{
|
||||
tga_source_ptr source = (tga_source_ptr) sinfo;
|
||||
JDIMENSION source_row;
|
||||
|
||||
/* Compute row of source that maps to current_row of normal order */
|
||||
/* For now, assume image is bottom-up and not interlaced. */
|
||||
/* NEEDS WORK to support interlaced images! */
|
||||
source_row = cinfo->image_height - source->current_row - 1;
|
||||
|
||||
/* Fetch that row from virtual array */
|
||||
source->pub.buffer = (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,
|
||||
source->whole_image, source_row, (JDIMENSION) 1, FALSE);
|
||||
|
||||
source->current_row++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This method loads the image into whole_image during the first call on
|
||||
* get_pixel_rows. The get_pixel_rows pointer is then adjusted to call
|
||||
* get_memory_row on subsequent calls.
|
||||
*/
|
||||
|
||||
METHODDEF(JDIMENSION)
|
||||
preload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
{
|
||||
tga_source_ptr source = (tga_source_ptr) sinfo;
|
||||
JDIMENSION row;
|
||||
cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
|
||||
|
||||
/* Read the data into a virtual array in input-file row order. */
|
||||
for (row = 0; row < cinfo->image_height; row++) {
|
||||
if (progress != NULL) {
|
||||
progress->pub.pass_counter = (long) row;
|
||||
progress->pub.pass_limit = (long) cinfo->image_height;
|
||||
(*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
|
||||
}
|
||||
source->pub.buffer = (*cinfo->mem->access_virt_sarray)
|
||||
((j_common_ptr) cinfo, source->whole_image, row, (JDIMENSION) 1, TRUE);
|
||||
(*source->get_pixel_rows) (cinfo, sinfo);
|
||||
}
|
||||
if (progress != NULL)
|
||||
progress->completed_extra_passes++;
|
||||
|
||||
/* Set up to read from the virtual array in unscrambled order */
|
||||
source->pub.get_pixel_rows = get_memory_row;
|
||||
source->current_row = 0;
|
||||
/* And read the first row */
|
||||
return get_memory_row(cinfo, sinfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read the file header; return image size and component count.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
start_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
{
|
||||
tga_source_ptr source = (tga_source_ptr) sinfo;
|
||||
U_CHAR targaheader[18];
|
||||
int idlen, cmaptype, subtype, flags, interlace_type, components;
|
||||
unsigned int width, height, maplen;
|
||||
boolean is_bottom_up;
|
||||
|
||||
#define GET_2B(offset) ((unsigned int) UCH(targaheader[offset]) + \
|
||||
(((unsigned int) UCH(targaheader[offset+1])) << 8))
|
||||
|
||||
if (! ReadOK(source->pub.input_file, targaheader, 18))
|
||||
ERREXIT(cinfo, JERR_INPUT_EOF);
|
||||
|
||||
/* Pretend "15-bit" pixels are 16-bit --- we ignore attribute bit anyway */
|
||||
if (targaheader[16] == 15)
|
||||
targaheader[16] = 16;
|
||||
|
||||
idlen = UCH(targaheader[0]);
|
||||
cmaptype = UCH(targaheader[1]);
|
||||
subtype = UCH(targaheader[2]);
|
||||
maplen = GET_2B(5);
|
||||
width = GET_2B(12);
|
||||
height = GET_2B(14);
|
||||
source->pixel_size = UCH(targaheader[16]) >> 3;
|
||||
flags = UCH(targaheader[17]); /* Image Descriptor byte */
|
||||
|
||||
is_bottom_up = ((flags & 0x20) == 0); /* bit 5 set => top-down */
|
||||
interlace_type = flags >> 6; /* bits 6/7 are interlace code */
|
||||
|
||||
if (cmaptype > 1 || /* cmaptype must be 0 or 1 */
|
||||
width <= 0 || height <= 0 ||
|
||||
source->pixel_size < 1 || source->pixel_size > 4 ||
|
||||
(UCH(targaheader[16]) & 7) != 0 || /* bits/pixel must be multiple of 8 */
|
||||
interlace_type != 0) /* currently don't allow interlaced image */
|
||||
ERREXIT(cinfo, JERR_TGA_BADPARMS);
|
||||
|
||||
if (subtype > 8) {
|
||||
/* It's an RLE-coded file */
|
||||
source->read_pixel = read_rle_pixel;
|
||||
source->block_count = source->dup_pixel_count = 0;
|
||||
subtype -= 8;
|
||||
} else {
|
||||
/* Non-RLE file */
|
||||
source->read_pixel = read_non_rle_pixel;
|
||||
}
|
||||
|
||||
/* Now should have subtype 1, 2, or 3 */
|
||||
components = 3; /* until proven different */
|
||||
cinfo->in_color_space = JCS_RGB;
|
||||
|
||||
switch (subtype) {
|
||||
case 1: /* Colormapped image */
|
||||
if (source->pixel_size == 1 && cmaptype == 1)
|
||||
source->get_pixel_rows = get_8bit_row;
|
||||
else
|
||||
ERREXIT(cinfo, JERR_TGA_BADPARMS);
|
||||
TRACEMS2(cinfo, 1, JTRC_TGA_MAPPED, width, height);
|
||||
break;
|
||||
case 2: /* RGB image */
|
||||
switch (source->pixel_size) {
|
||||
case 2:
|
||||
source->get_pixel_rows = get_16bit_row;
|
||||
break;
|
||||
case 3:
|
||||
source->get_pixel_rows = get_24bit_row;
|
||||
break;
|
||||
case 4:
|
||||
source->get_pixel_rows = get_32bit_row;
|
||||
break;
|
||||
default:
|
||||
ERREXIT(cinfo, JERR_TGA_BADPARMS);
|
||||
}
|
||||
TRACEMS2(cinfo, 1, JTRC_TGA, width, height);
|
||||
break;
|
||||
case 3: /* Grayscale image */
|
||||
components = 1;
|
||||
cinfo->in_color_space = JCS_GRAYSCALE;
|
||||
if (source->pixel_size == 1)
|
||||
source->get_pixel_rows = get_8bit_gray_row;
|
||||
else
|
||||
ERREXIT(cinfo, JERR_TGA_BADPARMS);
|
||||
TRACEMS2(cinfo, 1, JTRC_TGA_GRAY, width, height);
|
||||
break;
|
||||
default:
|
||||
ERREXIT(cinfo, JERR_TGA_BADPARMS);
|
||||
}
|
||||
|
||||
if (is_bottom_up) {
|
||||
/* Create a virtual array to buffer the upside-down image. */
|
||||
source->whole_image = (*cinfo->mem->request_virt_sarray)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
|
||||
(JDIMENSION) width * components, (JDIMENSION) height, (JDIMENSION) 1);
|
||||
if (cinfo->progress != NULL) {
|
||||
cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
|
||||
progress->total_extra_passes++; /* count file input as separate pass */
|
||||
}
|
||||
/* source->pub.buffer will point to the virtual array. */
|
||||
source->pub.buffer_height = 1; /* in case anyone looks at it */
|
||||
source->pub.get_pixel_rows = preload_image;
|
||||
} else {
|
||||
/* Don't need a virtual array, but do need a one-row input buffer. */
|
||||
source->whole_image = NULL;
|
||||
source->pub.buffer = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo,
|
||||
JPOOL_IMAGE, (JDIMENSION) width * components, (JDIMENSION) 1);
|
||||
source->pub.buffer_height = 1;
|
||||
source->pub.get_pixel_rows = source->get_pixel_rows;
|
||||
}
|
||||
|
||||
while (idlen--) /* Throw away ID field */
|
||||
(void) read_byte(source);
|
||||
|
||||
if (maplen > 0) {
|
||||
if (maplen > 256 || GET_2B(3) != 0)
|
||||
ERREXIT(cinfo, JERR_TGA_BADCMAP);
|
||||
/* Allocate space to store the colormap */
|
||||
source->colormap = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo,
|
||||
JPOOL_IMAGE, (JDIMENSION) maplen, (JDIMENSION) 3);
|
||||
source->cmap_length = (int) maplen;
|
||||
/* and read it from the file */
|
||||
read_colormap(source, (int) maplen, UCH(targaheader[7]));
|
||||
} else {
|
||||
if (cmaptype) /* but you promised a cmap! */
|
||||
ERREXIT(cinfo, JERR_TGA_BADPARMS);
|
||||
source->colormap = NULL;
|
||||
source->cmap_length = 0;
|
||||
}
|
||||
|
||||
cinfo->input_components = components;
|
||||
cinfo->data_precision = 8;
|
||||
cinfo->image_width = width;
|
||||
cinfo->image_height = height;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Finish up at the end of the file.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
finish_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
|
||||
{
|
||||
/* no work */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The module selection routine for Targa format input.
|
||||
*/
|
||||
|
||||
GLOBAL(cjpeg_source_ptr)
|
||||
jinit_read_targa (j_compress_ptr cinfo)
|
||||
{
|
||||
tga_source_ptr source;
|
||||
|
||||
/* Create module interface object */
|
||||
source = (tga_source_ptr) (*cinfo->mem->alloc_small)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(tga_source_struct));
|
||||
source->cinfo = cinfo; /* make back link for subroutines */
|
||||
/* Fill in method ptrs, except get_pixel_rows which start_input sets */
|
||||
source->pub.start_input = start_input_tga;
|
||||
source->pub.finish_input = finish_input_tga;
|
||||
|
||||
return &source->pub;
|
||||
}
|
||||
|
||||
#endif /* TARGA_SUPPORTED */
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,437 +0,0 @@
|
|||
/*
|
||||
* wrbmp.c
|
||||
*
|
||||
* Copyright (C) 1994-1996, Thomas G. Lane.
|
||||
* Modified 2017-2019 by Guido Vollbeding.
|
||||
* 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 routines to write output images in Microsoft "BMP"
|
||||
* format (MS Windows 3.x and OS/2 1.x flavors).
|
||||
* Either 8-bit colormapped or 24-bit full-color format can be written.
|
||||
* No compression is supported.
|
||||
*
|
||||
* These routines may need modification for non-Unix environments or
|
||||
* specialized applications. As they stand, they assume output to
|
||||
* an ordinary stdio stream.
|
||||
*
|
||||
* This code contributed by James Arthur Boucher.
|
||||
*/
|
||||
|
||||
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
||||
|
||||
#ifdef BMP_SUPPORTED
|
||||
|
||||
|
||||
/*
|
||||
* To support 12-bit JPEG data, we'd have to scale output down to 8 bits.
|
||||
* This is not yet implemented.
|
||||
*/
|
||||
|
||||
#if BITS_IN_JSAMPLE != 8
|
||||
Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Since BMP stores scanlines bottom-to-top, we have to invert the image
|
||||
* from JPEG's top-to-bottom order. To do this, we save the outgoing data
|
||||
* in a virtual array during put_pixel_row calls, then actually emit the
|
||||
* BMP file during finish_output. The virtual array contains one JSAMPLE per
|
||||
* pixel if the output is grayscale or colormapped, three if it is full color.
|
||||
*/
|
||||
|
||||
/* Private version of data destination object */
|
||||
|
||||
typedef struct {
|
||||
struct djpeg_dest_struct pub; /* public fields */
|
||||
|
||||
boolean is_os2; /* saves the OS2 format request flag */
|
||||
|
||||
jvirt_sarray_ptr whole_image; /* needed to reverse row order */
|
||||
JDIMENSION data_width; /* JSAMPLEs per row */
|
||||
JDIMENSION row_width; /* physical width of one row in the BMP file */
|
||||
int pad_bytes; /* number of padding bytes needed per row */
|
||||
JDIMENSION cur_output_row; /* next row# to write to virtual array */
|
||||
} bmp_dest_struct;
|
||||
|
||||
typedef bmp_dest_struct * bmp_dest_ptr;
|
||||
|
||||
|
||||
/* Forward declarations */
|
||||
LOCAL(void) write_colormap
|
||||
JPP((j_decompress_ptr cinfo, bmp_dest_ptr dest,
|
||||
int map_colors, int map_entry_size));
|
||||
|
||||
|
||||
/*
|
||||
* Write some pixel data.
|
||||
* In this module rows_supplied will always be 1.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
|
||||
JDIMENSION rows_supplied)
|
||||
/* This version is for writing 24-bit pixels */
|
||||
{
|
||||
bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
|
||||
register JSAMPROW inptr, outptr;
|
||||
register JDIMENSION col;
|
||||
int pad;
|
||||
|
||||
/* Access next row in virtual array */
|
||||
outptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,
|
||||
dest->whole_image, dest->cur_output_row, (JDIMENSION) 1, TRUE);
|
||||
dest->cur_output_row++;
|
||||
|
||||
/* Transfer data. Note destination values must be in BGR order
|
||||
* (even though Microsoft's own documents say the opposite).
|
||||
*/
|
||||
inptr = dest->pub.buffer[0];
|
||||
for (col = cinfo->output_width; col > 0; col--) {
|
||||
outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */
|
||||
outptr[1] = *inptr++;
|
||||
outptr[0] = *inptr++;
|
||||
outptr += 3;
|
||||
}
|
||||
|
||||
/* Zero out the pad bytes. */
|
||||
pad = dest->pad_bytes;
|
||||
while (--pad >= 0)
|
||||
*outptr++ = 0;
|
||||
}
|
||||
|
||||
METHODDEF(void)
|
||||
put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
|
||||
JDIMENSION rows_supplied)
|
||||
/* This version is for grayscale OR quantized color output */
|
||||
{
|
||||
bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
|
||||
register JSAMPROW inptr, outptr;
|
||||
register JDIMENSION col;
|
||||
int pad;
|
||||
|
||||
/* Access next row in virtual array */
|
||||
outptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,
|
||||
dest->whole_image, dest->cur_output_row, (JDIMENSION) 1, TRUE);
|
||||
dest->cur_output_row++;
|
||||
|
||||
/* Transfer data. */
|
||||
inptr = dest->pub.buffer[0];
|
||||
for (col = cinfo->output_width; col > 0; col--) {
|
||||
*outptr++ = *inptr++; /* can omit GETJSAMPLE() safely */
|
||||
}
|
||||
|
||||
/* Zero out the pad bytes. */
|
||||
pad = dest->pad_bytes;
|
||||
while (--pad >= 0)
|
||||
*outptr++ = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Startup: normally writes the file header.
|
||||
* In this module we may as well postpone everything until finish_output.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
start_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
|
||||
{
|
||||
/* no work here */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Finish up at the end of the file.
|
||||
*
|
||||
* Here is where we really output the BMP file.
|
||||
*
|
||||
* First, routines to write the Windows and OS/2 variants of the file header.
|
||||
*/
|
||||
|
||||
LOCAL(void)
|
||||
write_bmp_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)
|
||||
/* Write a Windows-style BMP file header, including colormap if needed */
|
||||
{
|
||||
char bmpfileheader[14];
|
||||
char bmpinfoheader[40];
|
||||
#define PUT_2B(array, offset, value) \
|
||||
(array[offset] = (char) ((value) & 0xFF), \
|
||||
array[offset+1] = (char) (((value) >> 8) & 0xFF))
|
||||
#define PUT_4B(array, offset, value) \
|
||||
(array[offset] = (char) ((value) & 0xFF), \
|
||||
array[offset+1] = (char) (((value) >> 8) & 0xFF), \
|
||||
array[offset+2] = (char) (((value) >> 16) & 0xFF), \
|
||||
array[offset+3] = (char) (((value) >> 24) & 0xFF))
|
||||
INT32 headersize, bfSize;
|
||||
int bits_per_pixel, cmap_entries;
|
||||
|
||||
/* Compute colormap size and total file size */
|
||||
if (cinfo->out_color_space == JCS_RGB) {
|
||||
if (cinfo->quantize_colors) {
|
||||
/* Colormapped RGB */
|
||||
bits_per_pixel = 8;
|
||||
cmap_entries = 256;
|
||||
} else {
|
||||
/* Unquantized, full color RGB */
|
||||
bits_per_pixel = 24;
|
||||
cmap_entries = 0;
|
||||
}
|
||||
} else {
|
||||
/* Grayscale output. We need to fake a 256-entry colormap. */
|
||||
bits_per_pixel = 8;
|
||||
cmap_entries = 256;
|
||||
}
|
||||
/* File size */
|
||||
headersize = 14 + 40 + cmap_entries * 4; /* Header and colormap */
|
||||
bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height;
|
||||
|
||||
/* Set unused fields of header to 0 */
|
||||
MEMZERO(bmpfileheader, SIZEOF(bmpfileheader));
|
||||
MEMZERO(bmpinfoheader, SIZEOF(bmpinfoheader));
|
||||
|
||||
/* Fill the file header */
|
||||
bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */
|
||||
bmpfileheader[1] = 0x4D;
|
||||
PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */
|
||||
/* we leave bfReserved1 & bfReserved2 = 0 */
|
||||
PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */
|
||||
|
||||
/* Fill the info header (Microsoft calls this a BITMAPINFOHEADER) */
|
||||
PUT_2B(bmpinfoheader, 0, 40); /* biSize */
|
||||
PUT_4B(bmpinfoheader, 4, cinfo->output_width); /* biWidth */
|
||||
PUT_4B(bmpinfoheader, 8, cinfo->output_height); /* biHeight */
|
||||
PUT_2B(bmpinfoheader, 12, 1); /* biPlanes - must be 1 */
|
||||
PUT_2B(bmpinfoheader, 14, bits_per_pixel); /* biBitCount */
|
||||
/* we leave biCompression = 0, for none */
|
||||
/* we leave biSizeImage = 0; this is correct for uncompressed data */
|
||||
if (cinfo->density_unit == 2) { /* if have density in dots/cm, then */
|
||||
PUT_4B(bmpinfoheader, 24, (INT32) (cinfo->X_density*100)); /* XPels/M */
|
||||
PUT_4B(bmpinfoheader, 28, (INT32) (cinfo->Y_density*100)); /* XPels/M */
|
||||
}
|
||||
PUT_2B(bmpinfoheader, 32, cmap_entries); /* biClrUsed */
|
||||
/* we leave biClrImportant = 0 */
|
||||
|
||||
if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14)
|
||||
ERREXIT(cinfo, JERR_FILE_WRITE);
|
||||
if (JFWRITE(dest->pub.output_file, bmpinfoheader, 40) != (size_t) 40)
|
||||
ERREXIT(cinfo, JERR_FILE_WRITE);
|
||||
|
||||
if (cmap_entries > 0)
|
||||
write_colormap(cinfo, dest, cmap_entries, 4);
|
||||
}
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
write_os2_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)
|
||||
/* Write an OS2-style BMP file header, including colormap if needed */
|
||||
{
|
||||
char bmpfileheader[14];
|
||||
char bmpcoreheader[12];
|
||||
INT32 headersize, bfSize;
|
||||
int bits_per_pixel, cmap_entries;
|
||||
|
||||
/* Compute colormap size and total file size */
|
||||
if (cinfo->out_color_space == JCS_RGB) {
|
||||
if (cinfo->quantize_colors) {
|
||||
/* Colormapped RGB */
|
||||
bits_per_pixel = 8;
|
||||
cmap_entries = 256;
|
||||
} else {
|
||||
/* Unquantized, full color RGB */
|
||||
bits_per_pixel = 24;
|
||||
cmap_entries = 0;
|
||||
}
|
||||
} else {
|
||||
/* Grayscale output. We need to fake a 256-entry colormap. */
|
||||
bits_per_pixel = 8;
|
||||
cmap_entries = 256;
|
||||
}
|
||||
/* File size */
|
||||
headersize = 14 + 12 + cmap_entries * 3; /* Header and colormap */
|
||||
bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height;
|
||||
|
||||
/* Set unused fields of header to 0 */
|
||||
MEMZERO(bmpfileheader, SIZEOF(bmpfileheader));
|
||||
MEMZERO(bmpcoreheader, SIZEOF(bmpcoreheader));
|
||||
|
||||
/* Fill the file header */
|
||||
bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */
|
||||
bmpfileheader[1] = 0x4D;
|
||||
PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */
|
||||
/* we leave bfReserved1 & bfReserved2 = 0 */
|
||||
PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */
|
||||
|
||||
/* Fill the info header (Microsoft calls this a BITMAPCOREHEADER) */
|
||||
PUT_2B(bmpcoreheader, 0, 12); /* bcSize */
|
||||
PUT_2B(bmpcoreheader, 4, cinfo->output_width); /* bcWidth */
|
||||
PUT_2B(bmpcoreheader, 6, cinfo->output_height); /* bcHeight */
|
||||
PUT_2B(bmpcoreheader, 8, 1); /* bcPlanes - must be 1 */
|
||||
PUT_2B(bmpcoreheader, 10, bits_per_pixel); /* bcBitCount */
|
||||
|
||||
if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14)
|
||||
ERREXIT(cinfo, JERR_FILE_WRITE);
|
||||
if (JFWRITE(dest->pub.output_file, bmpcoreheader, 12) != (size_t) 12)
|
||||
ERREXIT(cinfo, JERR_FILE_WRITE);
|
||||
|
||||
if (cmap_entries > 0)
|
||||
write_colormap(cinfo, dest, cmap_entries, 3);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write the colormap.
|
||||
* Windows uses BGR0 map entries; OS/2 uses BGR entries.
|
||||
*/
|
||||
|
||||
LOCAL(void)
|
||||
write_colormap (j_decompress_ptr cinfo, bmp_dest_ptr dest,
|
||||
int map_colors, int map_entry_size)
|
||||
{
|
||||
JSAMPARRAY colormap = cinfo->colormap;
|
||||
int num_colors = cinfo->actual_number_of_colors;
|
||||
FILE * outfile = dest->pub.output_file;
|
||||
int i;
|
||||
|
||||
if (colormap != NULL) {
|
||||
if (cinfo->out_color_components == 3) {
|
||||
/* Normal case with RGB colormap */
|
||||
for (i = 0; i < num_colors; i++) {
|
||||
putc(GETJSAMPLE(colormap[2][i]), outfile);
|
||||
putc(GETJSAMPLE(colormap[1][i]), outfile);
|
||||
putc(GETJSAMPLE(colormap[0][i]), outfile);
|
||||
if (map_entry_size == 4)
|
||||
putc(0, outfile);
|
||||
}
|
||||
} else {
|
||||
/* Grayscale colormap (only happens with grayscale quantization) */
|
||||
for (i = 0; i < num_colors; i++) {
|
||||
putc(GETJSAMPLE(colormap[0][i]), outfile);
|
||||
putc(GETJSAMPLE(colormap[0][i]), outfile);
|
||||
putc(GETJSAMPLE(colormap[0][i]), outfile);
|
||||
if (map_entry_size == 4)
|
||||
putc(0, outfile);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* If no colormap, must be grayscale data. Generate a linear "map". */
|
||||
for (i = 0; i < 256; i++) {
|
||||
putc(i, outfile);
|
||||
putc(i, outfile);
|
||||
putc(i, outfile);
|
||||
if (map_entry_size == 4)
|
||||
putc(0, outfile);
|
||||
}
|
||||
}
|
||||
/* Pad colormap to ensure specified number of colormap entries */
|
||||
if (i > map_colors)
|
||||
ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, i);
|
||||
for (; i < map_colors; i++) {
|
||||
putc(CENTERJSAMPLE, outfile);
|
||||
putc(CENTERJSAMPLE, outfile);
|
||||
putc(CENTERJSAMPLE, outfile);
|
||||
if (map_entry_size == 4)
|
||||
putc(0, outfile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
finish_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
|
||||
{
|
||||
bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
|
||||
register FILE * outfile = dest->pub.output_file;
|
||||
register JSAMPROW data_ptr;
|
||||
JDIMENSION row;
|
||||
register JDIMENSION col;
|
||||
cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
|
||||
|
||||
/* Write the header and colormap */
|
||||
if (dest->is_os2)
|
||||
write_os2_header(cinfo, dest);
|
||||
else
|
||||
write_bmp_header(cinfo, dest);
|
||||
|
||||
/* Write the file body from our virtual array */
|
||||
for (row = cinfo->output_height; row > 0; row--) {
|
||||
if (progress != NULL) {
|
||||
progress->pub.pass_counter = (long) (cinfo->output_height - row);
|
||||
progress->pub.pass_limit = (long) cinfo->output_height;
|
||||
(*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
|
||||
}
|
||||
data_ptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,
|
||||
dest->whole_image, row - 1, (JDIMENSION) 1, FALSE);
|
||||
for (col = dest->row_width; col > 0; col--) {
|
||||
putc(GETJSAMPLE(*data_ptr), outfile);
|
||||
data_ptr++;
|
||||
}
|
||||
}
|
||||
if (progress != NULL)
|
||||
progress->completed_extra_passes++;
|
||||
|
||||
/* Make sure we wrote the output file OK */
|
||||
JFFLUSH(outfile);
|
||||
if (JFERROR(outfile))
|
||||
ERREXIT(cinfo, JERR_FILE_WRITE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The module selection routine for BMP format output.
|
||||
*/
|
||||
|
||||
GLOBAL(djpeg_dest_ptr)
|
||||
jinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2)
|
||||
{
|
||||
bmp_dest_ptr dest;
|
||||
JDIMENSION row_width;
|
||||
|
||||
/* Create module interface object, fill in method pointers */
|
||||
dest = (bmp_dest_ptr) (*cinfo->mem->alloc_small)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(bmp_dest_struct));
|
||||
dest->pub.start_output = start_output_bmp;
|
||||
dest->pub.finish_output = finish_output_bmp;
|
||||
dest->is_os2 = is_os2;
|
||||
|
||||
switch (cinfo->out_color_space) {
|
||||
case JCS_GRAYSCALE:
|
||||
dest->pub.put_pixel_rows = put_gray_rows;
|
||||
break;
|
||||
case JCS_RGB:
|
||||
if (cinfo->quantize_colors)
|
||||
dest->pub.put_pixel_rows = put_gray_rows;
|
||||
else
|
||||
dest->pub.put_pixel_rows = put_pixel_rows;
|
||||
break;
|
||||
default:
|
||||
ERREXIT(cinfo, JERR_BMP_COLORSPACE);
|
||||
}
|
||||
|
||||
/* Calculate output image dimensions so we can allocate space */
|
||||
jpeg_calc_output_dimensions(cinfo);
|
||||
|
||||
/* Determine width of rows in the BMP file (padded to 4-byte boundary). */
|
||||
row_width = cinfo->output_width * cinfo->output_components;
|
||||
dest->data_width = row_width;
|
||||
while ((row_width & 3) != 0) row_width++;
|
||||
dest->row_width = row_width;
|
||||
dest->pad_bytes = (int) (row_width - dest->data_width);
|
||||
|
||||
/* Allocate space for inversion array, prepare for write pass */
|
||||
dest->whole_image = (*cinfo->mem->request_virt_sarray)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
|
||||
row_width, cinfo->output_height, (JDIMENSION) 1);
|
||||
dest->cur_output_row = 0;
|
||||
if (cinfo->progress != NULL) {
|
||||
cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
|
||||
progress->total_extra_passes++; /* count file input as separate pass */
|
||||
}
|
||||
|
||||
/* Create decompressor output buffer. */
|
||||
dest->pub.buffer = (*cinfo->mem->alloc_sarray)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, row_width, (JDIMENSION) 1);
|
||||
dest->pub.buffer_height = 1;
|
||||
|
||||
return &dest->pub;
|
||||
}
|
||||
|
||||
#endif /* BMP_SUPPORTED */
|
||||
|
|
@ -1,566 +0,0 @@
|
|||
/*
|
||||
* wrgif.c
|
||||
*
|
||||
* Copyright (C) 1991-1996, Thomas G. Lane.
|
||||
* Modified 2015-2019 by Guido Vollbeding.
|
||||
* 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 routines to write output images in GIF format.
|
||||
*
|
||||
* These routines may need modification for non-Unix environments or
|
||||
* specialized applications. As they stand, they assume output to
|
||||
* an ordinary stdio stream.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is loosely based on ppmtogif from the PBMPLUS distribution
|
||||
* of Feb. 1991. That file contains the following copyright notice:
|
||||
* Based on GIFENCODE by David Rowley <mgardi@watdscu.waterloo.edu>.
|
||||
* Lempel-Ziv compression based on "compress" by Spencer W. Thomas et al.
|
||||
* Copyright (C) 1989 by Jef Poskanzer.
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation for any purpose and without fee is hereby granted, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation. This software is provided "as is" without express or
|
||||
* implied warranty.
|
||||
*/
|
||||
|
||||
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
||||
|
||||
#ifdef GIF_SUPPORTED
|
||||
|
||||
|
||||
#define MAX_LZW_BITS 12 /* maximum LZW code size (4096 symbols) */
|
||||
|
||||
typedef INT16 code_int; /* must hold -1 .. 2**MAX_LZW_BITS */
|
||||
|
||||
#define LZW_TABLE_SIZE ((code_int) 1 << MAX_LZW_BITS)
|
||||
|
||||
#define HSIZE 5003 /* hash table size for 80% occupancy */
|
||||
|
||||
typedef int hash_int; /* must hold -2*HSIZE..2*HSIZE */
|
||||
|
||||
#define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1)
|
||||
|
||||
|
||||
/*
|
||||
* The LZW hash table consists of two parallel arrays:
|
||||
* hash_code[i] code of symbol in slot i, or 0 if empty slot
|
||||
* hash_value[i] symbol's value; undefined if empty slot
|
||||
* where slot values (i) range from 0 to HSIZE-1. The symbol value is
|
||||
* its prefix symbol's code concatenated with its suffix character.
|
||||
*
|
||||
* Algorithm: use open addressing double hashing (no chaining) on the
|
||||
* prefix code / suffix character combination. We do a variant of Knuth's
|
||||
* algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
|
||||
* secondary probe.
|
||||
*
|
||||
* The hash_value[] table is allocated from FAR heap space since it would
|
||||
* use up rather a lot of the near data space in a PC.
|
||||
*/
|
||||
|
||||
typedef INT32 hash_entry; /* must hold (code_int<<8) | byte */
|
||||
|
||||
#define HASH_ENTRY(prefix, suffix) ((((hash_entry) (prefix)) << 8) | (suffix))
|
||||
|
||||
|
||||
/* Private version of data destination object */
|
||||
|
||||
typedef struct {
|
||||
struct djpeg_dest_struct pub; /* public fields */
|
||||
|
||||
j_decompress_ptr cinfo; /* back link saves passing separate parm */
|
||||
|
||||
/* State for packing variable-width codes into a bitstream */
|
||||
int n_bits; /* current number of bits/code */
|
||||
code_int maxcode; /* maximum code, given n_bits */
|
||||
int init_bits; /* initial n_bits ... restored after clear */
|
||||
INT32 cur_accum; /* holds bits not yet output */
|
||||
int cur_bits; /* # of bits in cur_accum */
|
||||
|
||||
/* LZW string construction */
|
||||
code_int waiting_code; /* symbol not yet output; may be extendable */
|
||||
boolean first_byte; /* if TRUE, waiting_code is not valid */
|
||||
|
||||
/* State for GIF code assignment */
|
||||
code_int ClearCode; /* clear code (doesn't change) */
|
||||
code_int EOFCode; /* EOF code (ditto) */
|
||||
code_int free_code; /* LZW: first not-yet-used symbol code */
|
||||
code_int code_counter; /* not LZW: counts output symbols */
|
||||
|
||||
/* LZW hash table */
|
||||
code_int *hash_code; /* => hash table of symbol codes */
|
||||
hash_entry FAR *hash_value; /* => hash table of symbol values */
|
||||
|
||||
/* GIF data packet construction buffer */
|
||||
int bytesinpkt; /* # of bytes in current packet */
|
||||
char packetbuf[256]; /* workspace for accumulating packet */
|
||||
|
||||
} gif_dest_struct;
|
||||
|
||||
typedef gif_dest_struct * gif_dest_ptr;
|
||||
|
||||
|
||||
/*
|
||||
* Routines to package finished data bytes into GIF data blocks.
|
||||
* A data block consists of a count byte (1..255) and that many data bytes.
|
||||
*/
|
||||
|
||||
LOCAL(void)
|
||||
flush_packet (gif_dest_ptr dinfo)
|
||||
/* flush any accumulated data */
|
||||
{
|
||||
if (dinfo->bytesinpkt > 0) { /* never write zero-length packet */
|
||||
dinfo->packetbuf[0] = (char) dinfo->bytesinpkt++;
|
||||
if (JFWRITE(dinfo->pub.output_file, dinfo->packetbuf, dinfo->bytesinpkt)
|
||||
!= (size_t) dinfo->bytesinpkt)
|
||||
ERREXIT(dinfo->cinfo, JERR_FILE_WRITE);
|
||||
dinfo->bytesinpkt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Add a character to current packet; flush to disk if necessary */
|
||||
#define CHAR_OUT(dinfo, c) \
|
||||
{ (dinfo)->packetbuf[++(dinfo)->bytesinpkt] = (char) (c); \
|
||||
if ((dinfo)->bytesinpkt >= 255) \
|
||||
flush_packet(dinfo); \
|
||||
}
|
||||
|
||||
|
||||
/* Routine to convert variable-width codes into a byte stream */
|
||||
|
||||
LOCAL(void)
|
||||
output (gif_dest_ptr dinfo, code_int code)
|
||||
/* Emit a code of n_bits bits */
|
||||
/* Uses cur_accum and cur_bits to reblock into 8-bit bytes */
|
||||
{
|
||||
dinfo->cur_accum |= ((INT32) code) << dinfo->cur_bits;
|
||||
dinfo->cur_bits += dinfo->n_bits;
|
||||
|
||||
while (dinfo->cur_bits >= 8) {
|
||||
CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF);
|
||||
dinfo->cur_accum >>= 8;
|
||||
dinfo->cur_bits -= 8;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the next entry is going to be too big for the code size,
|
||||
* then increase it, if possible. We do this here to ensure
|
||||
* that it's done in sync with the decoder's codesize increases.
|
||||
*/
|
||||
if (dinfo->free_code > dinfo->maxcode) {
|
||||
dinfo->n_bits++;
|
||||
if (dinfo->n_bits == MAX_LZW_BITS)
|
||||
dinfo->maxcode = LZW_TABLE_SIZE; /* free_code will never exceed this */
|
||||
else
|
||||
dinfo->maxcode = MAXCODE(dinfo->n_bits);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Compression initialization & termination */
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
clear_hash (gif_dest_ptr dinfo)
|
||||
/* Fill the hash table with empty entries */
|
||||
{
|
||||
/* It's sufficient to zero hash_code[] */
|
||||
MEMZERO(dinfo->hash_code, HSIZE * SIZEOF(code_int));
|
||||
}
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
clear_block (gif_dest_ptr dinfo)
|
||||
/* Reset compressor and issue a Clear code */
|
||||
{
|
||||
clear_hash(dinfo); /* delete all the symbols */
|
||||
dinfo->free_code = dinfo->ClearCode + 2;
|
||||
output(dinfo, dinfo->ClearCode); /* inform decoder */
|
||||
dinfo->n_bits = dinfo->init_bits; /* reset code size */
|
||||
dinfo->maxcode = MAXCODE(dinfo->n_bits);
|
||||
}
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
compress_init (gif_dest_ptr dinfo, int i_bits)
|
||||
/* Initialize compressor */
|
||||
{
|
||||
/* init all the state variables */
|
||||
dinfo->n_bits = dinfo->init_bits = i_bits;
|
||||
dinfo->maxcode = MAXCODE(dinfo->n_bits);
|
||||
dinfo->ClearCode = ((code_int) 1 << (i_bits - 1));
|
||||
dinfo->EOFCode = dinfo->ClearCode + 1;
|
||||
dinfo->code_counter = dinfo->free_code = dinfo->ClearCode + 2;
|
||||
dinfo->first_byte = TRUE; /* no waiting symbol yet */
|
||||
/* init output buffering vars */
|
||||
dinfo->bytesinpkt = 0;
|
||||
dinfo->cur_accum = 0;
|
||||
dinfo->cur_bits = 0;
|
||||
/* clear hash table */
|
||||
if (dinfo->hash_code != NULL)
|
||||
clear_hash(dinfo);
|
||||
/* GIF specifies an initial Clear code */
|
||||
output(dinfo, dinfo->ClearCode);
|
||||
}
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
compress_term (gif_dest_ptr dinfo)
|
||||
/* Clean up at end */
|
||||
{
|
||||
/* Flush out the buffered LZW code */
|
||||
if (! dinfo->first_byte)
|
||||
output(dinfo, dinfo->waiting_code);
|
||||
/* Send an EOF code */
|
||||
output(dinfo, dinfo->EOFCode);
|
||||
/* Flush the bit-packing buffer */
|
||||
if (dinfo->cur_bits > 0) {
|
||||
CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF);
|
||||
}
|
||||
/* Flush the packet buffer */
|
||||
flush_packet(dinfo);
|
||||
}
|
||||
|
||||
|
||||
/* GIF header construction */
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
put_word (gif_dest_ptr dinfo, unsigned int w)
|
||||
/* Emit a 16-bit word, LSB first */
|
||||
{
|
||||
putc(w & 0xFF, dinfo->pub.output_file);
|
||||
putc((w >> 8) & 0xFF, dinfo->pub.output_file);
|
||||
}
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
put_3bytes (gif_dest_ptr dinfo, int val)
|
||||
/* Emit 3 copies of same byte value --- handy subr for colormap construction */
|
||||
{
|
||||
putc(val, dinfo->pub.output_file);
|
||||
putc(val, dinfo->pub.output_file);
|
||||
putc(val, dinfo->pub.output_file);
|
||||
}
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
emit_header (gif_dest_ptr dinfo, int num_colors, JSAMPARRAY colormap)
|
||||
/* Output the GIF file header, including color map */
|
||||
/* If colormap == NULL, synthesize a grayscale colormap */
|
||||
{
|
||||
int BitsPerPixel, ColorMapSize, InitCodeSize, FlagByte;
|
||||
int cshift = dinfo->cinfo->data_precision - 8;
|
||||
int i;
|
||||
|
||||
if (num_colors > 256)
|
||||
ERREXIT1(dinfo->cinfo, JERR_TOO_MANY_COLORS, num_colors);
|
||||
/* Compute bits/pixel and related values */
|
||||
BitsPerPixel = 1;
|
||||
while (num_colors > (1 << BitsPerPixel))
|
||||
BitsPerPixel++;
|
||||
ColorMapSize = 1 << BitsPerPixel;
|
||||
if (BitsPerPixel <= 1)
|
||||
InitCodeSize = 2;
|
||||
else
|
||||
InitCodeSize = BitsPerPixel;
|
||||
/*
|
||||
* Write the GIF header.
|
||||
* Note that we generate a plain GIF87 header for maximum compatibility.
|
||||
*/
|
||||
putc('G', dinfo->pub.output_file);
|
||||
putc('I', dinfo->pub.output_file);
|
||||
putc('F', dinfo->pub.output_file);
|
||||
putc('8', dinfo->pub.output_file);
|
||||
putc('7', dinfo->pub.output_file);
|
||||
putc('a', dinfo->pub.output_file);
|
||||
/* Write the Logical Screen Descriptor */
|
||||
put_word(dinfo, (unsigned int) dinfo->cinfo->output_width);
|
||||
put_word(dinfo, (unsigned int) dinfo->cinfo->output_height);
|
||||
FlagByte = 0x80; /* Yes, there is a global color table */
|
||||
FlagByte |= (BitsPerPixel - 1) << 4; /* color resolution */
|
||||
FlagByte |= (BitsPerPixel - 1); /* size of global color table */
|
||||
putc(FlagByte, dinfo->pub.output_file);
|
||||
putc(0, dinfo->pub.output_file); /* Background color index */
|
||||
putc(0, dinfo->pub.output_file); /* Reserved (aspect ratio in GIF89) */
|
||||
/* Write the Global Color Map */
|
||||
/* If the color map is more than 8 bits precision, */
|
||||
/* we reduce it to 8 bits by shifting */
|
||||
for (i = 0; i < ColorMapSize; i++) {
|
||||
if (i < num_colors) {
|
||||
if (colormap != NULL) {
|
||||
if (dinfo->cinfo->out_color_space == JCS_RGB) {
|
||||
/* Normal case: RGB color map */
|
||||
putc(GETJSAMPLE(colormap[0][i]) >> cshift, dinfo->pub.output_file);
|
||||
putc(GETJSAMPLE(colormap[1][i]) >> cshift, dinfo->pub.output_file);
|
||||
putc(GETJSAMPLE(colormap[2][i]) >> cshift, dinfo->pub.output_file);
|
||||
} else {
|
||||
/* Grayscale "color map": possible if quantizing grayscale image */
|
||||
put_3bytes(dinfo, GETJSAMPLE(colormap[0][i]) >> cshift);
|
||||
}
|
||||
} else {
|
||||
/* Create a grayscale map of num_colors values, range 0..255 */
|
||||
put_3bytes(dinfo, (i * 255 + (num_colors - 1) / 2) / (num_colors - 1));
|
||||
}
|
||||
} else {
|
||||
/* fill out the map to a power of 2 */
|
||||
put_3bytes(dinfo, CENTERJSAMPLE >> cshift);
|
||||
}
|
||||
}
|
||||
/* Write image separator and Image Descriptor */
|
||||
putc(',', dinfo->pub.output_file); /* separator */
|
||||
put_word(dinfo, 0); /* left/top offset */
|
||||
put_word(dinfo, 0);
|
||||
put_word(dinfo, (unsigned int) dinfo->cinfo->output_width); /* image size */
|
||||
put_word(dinfo, (unsigned int) dinfo->cinfo->output_height);
|
||||
/* flag byte: not interlaced, no local color map */
|
||||
putc(0x00, dinfo->pub.output_file);
|
||||
/* Write Initial Code Size byte */
|
||||
putc(InitCodeSize, dinfo->pub.output_file);
|
||||
|
||||
/* Initialize for compression of image data */
|
||||
compress_init(dinfo, InitCodeSize + 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Startup: write the file header.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
start_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
|
||||
{
|
||||
gif_dest_ptr dest = (gif_dest_ptr) dinfo;
|
||||
|
||||
if (cinfo->quantize_colors)
|
||||
emit_header(dest, cinfo->actual_number_of_colors, cinfo->colormap);
|
||||
else
|
||||
emit_header(dest, 256, (JSAMPARRAY) NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write some pixel data.
|
||||
* In this module rows_supplied will always be 1.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* The LZW algorithm proper
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
put_LZW_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
|
||||
JDIMENSION rows_supplied)
|
||||
{
|
||||
gif_dest_ptr dest = (gif_dest_ptr) dinfo;
|
||||
register JSAMPROW ptr;
|
||||
register JDIMENSION col;
|
||||
code_int c;
|
||||
register hash_int i;
|
||||
register hash_int disp;
|
||||
register hash_entry probe_value;
|
||||
|
||||
ptr = dest->pub.buffer[0];
|
||||
for (col = cinfo->output_width; col > 0; col--) {
|
||||
/* Accept and compress one 8-bit byte */
|
||||
c = (code_int) GETJSAMPLE(*ptr++);
|
||||
|
||||
if (dest->first_byte) { /* need to initialize waiting_code */
|
||||
dest->waiting_code = c;
|
||||
dest->first_byte = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Probe hash table to see if a symbol exists for
|
||||
* waiting_code followed by c.
|
||||
* If so, replace waiting_code by that symbol and continue.
|
||||
*/
|
||||
i = ((hash_int) c << (MAX_LZW_BITS-8)) + dest->waiting_code;
|
||||
/* i is less than twice 2**MAX_LZW_BITS, therefore less than twice HSIZE */
|
||||
if (i >= HSIZE)
|
||||
i -= HSIZE;
|
||||
|
||||
probe_value = HASH_ENTRY(dest->waiting_code, c);
|
||||
|
||||
if (dest->hash_code[i] == 0) {
|
||||
/* hit empty slot; desired symbol not in table */
|
||||
output(dest, dest->waiting_code);
|
||||
if (dest->free_code < LZW_TABLE_SIZE) {
|
||||
dest->hash_code[i] = dest->free_code++; /* add symbol to hashtable */
|
||||
dest->hash_value[i] = probe_value;
|
||||
} else
|
||||
clear_block(dest);
|
||||
dest->waiting_code = c;
|
||||
continue;
|
||||
}
|
||||
if (dest->hash_value[i] == probe_value) {
|
||||
dest->waiting_code = dest->hash_code[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == 0) /* secondary hash (after G. Knott) */
|
||||
disp = 1;
|
||||
else
|
||||
disp = HSIZE - i;
|
||||
for (;;) {
|
||||
i -= disp;
|
||||
if (i < 0)
|
||||
i += HSIZE;
|
||||
if (dest->hash_code[i] == 0) {
|
||||
/* hit empty slot; desired symbol not in table */
|
||||
output(dest, dest->waiting_code);
|
||||
if (dest->free_code < LZW_TABLE_SIZE) {
|
||||
dest->hash_code[i] = dest->free_code++; /* add symbol to hashtable */
|
||||
dest->hash_value[i] = probe_value;
|
||||
} else
|
||||
clear_block(dest);
|
||||
dest->waiting_code = c;
|
||||
break;
|
||||
}
|
||||
if (dest->hash_value[i] == probe_value) {
|
||||
dest->waiting_code = dest->hash_code[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The pseudo-compression algorithm.
|
||||
*
|
||||
* In this version we simply output each pixel value as a separate symbol;
|
||||
* thus, no compression occurs. In fact, there is expansion of one bit per
|
||||
* pixel, because we use a symbol width one bit wider than the pixel width.
|
||||
*
|
||||
* GIF ordinarily uses variable-width symbols, and the decoder will expect
|
||||
* to ratchet up the symbol width after a fixed number of symbols.
|
||||
* To simplify the logic and keep the expansion penalty down, we emit a
|
||||
* GIF Clear code to reset the decoder just before the width would ratchet up.
|
||||
* Thus, all the symbols in the output file will have the same bit width.
|
||||
* Note that emitting the Clear codes at the right times is a mere matter of
|
||||
* counting output symbols and is in no way dependent on the LZW algorithm.
|
||||
*
|
||||
* With a small basic pixel width (low color count), Clear codes will be
|
||||
* needed very frequently, causing the file to expand even more. So this
|
||||
* simplistic approach wouldn't work too well on bilevel images, for example.
|
||||
* But for output of JPEG conversions the pixel width will usually be 8 bits
|
||||
* (129 to 256 colors), so the overhead added by Clear symbols is only about
|
||||
* one symbol in every 256.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
put_raw_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
|
||||
JDIMENSION rows_supplied)
|
||||
{
|
||||
gif_dest_ptr dest = (gif_dest_ptr) dinfo;
|
||||
register JSAMPROW ptr;
|
||||
register JDIMENSION col;
|
||||
code_int c;
|
||||
|
||||
ptr = dest->pub.buffer[0];
|
||||
for (col = cinfo->output_width; col > 0; col--) {
|
||||
c = (code_int) GETJSAMPLE(*ptr++);
|
||||
/* Accept and output one pixel value.
|
||||
* The given value must be less than n_bits wide.
|
||||
*/
|
||||
|
||||
/* Output the given pixel value as a symbol. */
|
||||
output(dest, c);
|
||||
/* Issue Clear codes often enough to keep the reader from ratcheting up
|
||||
* its symbol size.
|
||||
*/
|
||||
if (dest->code_counter < dest->maxcode) {
|
||||
dest->code_counter++;
|
||||
} else {
|
||||
output(dest, dest->ClearCode);
|
||||
dest->code_counter = dest->ClearCode + 2; /* reset the counter */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Finish up at the end of the file.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
finish_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
|
||||
{
|
||||
gif_dest_ptr dest = (gif_dest_ptr) dinfo;
|
||||
|
||||
/* Flush compression mechanism */
|
||||
compress_term(dest);
|
||||
/* Write a zero-length data block to end the series */
|
||||
putc(0, dest->pub.output_file);
|
||||
/* Write the GIF terminator mark */
|
||||
putc(';', dest->pub.output_file);
|
||||
/* Make sure we wrote the output file OK */
|
||||
JFFLUSH(dest->pub.output_file);
|
||||
if (JFERROR(dest->pub.output_file))
|
||||
ERREXIT(cinfo, JERR_FILE_WRITE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The module selection routine for GIF format output.
|
||||
*/
|
||||
|
||||
GLOBAL(djpeg_dest_ptr)
|
||||
jinit_write_gif (j_decompress_ptr cinfo, boolean is_lzw)
|
||||
{
|
||||
gif_dest_ptr dest;
|
||||
|
||||
/* Create module interface object, fill in method pointers */
|
||||
dest = (gif_dest_ptr) (*cinfo->mem->alloc_small)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(gif_dest_struct));
|
||||
dest->cinfo = cinfo; /* make back link for subroutines */
|
||||
dest->pub.start_output = start_output_gif;
|
||||
dest->pub.finish_output = finish_output_gif;
|
||||
|
||||
if (cinfo->out_color_space != JCS_GRAYSCALE &&
|
||||
cinfo->out_color_space != JCS_RGB)
|
||||
ERREXIT(cinfo, JERR_GIF_COLORSPACE);
|
||||
|
||||
/* Force quantization if color or if > 8 bits input */
|
||||
if (cinfo->out_color_space != JCS_GRAYSCALE || cinfo->data_precision > 8) {
|
||||
/* Force quantization to at most 256 colors */
|
||||
cinfo->quantize_colors = TRUE;
|
||||
if (cinfo->desired_number_of_colors > 256)
|
||||
cinfo->desired_number_of_colors = 256;
|
||||
}
|
||||
|
||||
/* Calculate output image dimensions so we can allocate space */
|
||||
jpeg_calc_output_dimensions(cinfo);
|
||||
|
||||
if (cinfo->output_components != 1) /* safety check: just one component? */
|
||||
ERREXIT(cinfo, JERR_GIF_BUG);
|
||||
|
||||
/* Create decompressor output buffer. */
|
||||
dest->pub.buffer = (*cinfo->mem->alloc_sarray)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, cinfo->output_width, (JDIMENSION) 1);
|
||||
dest->pub.buffer_height = 1;
|
||||
|
||||
if (is_lzw) {
|
||||
dest->pub.put_pixel_rows = put_LZW_pixel_rows;
|
||||
/* Allocate space for hash table */
|
||||
dest->hash_code = (code_int *) (*cinfo->mem->alloc_small)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, HSIZE * SIZEOF(code_int));
|
||||
dest->hash_value = (hash_entry FAR *) (*cinfo->mem->alloc_large)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, HSIZE * SIZEOF(hash_entry));
|
||||
} else {
|
||||
dest->pub.put_pixel_rows = put_raw_pixel_rows;
|
||||
/* Mark tables unused */
|
||||
dest->hash_code = NULL;
|
||||
dest->hash_value = NULL;
|
||||
}
|
||||
|
||||
return &dest->pub;
|
||||
}
|
||||
|
||||
#endif /* GIF_SUPPORTED */
|
||||
|
|
@ -1,599 +0,0 @@
|
|||
/*
|
||||
* wrjpgcom.c
|
||||
*
|
||||
* Copyright (C) 1994-1997, Thomas G. Lane.
|
||||
* Modified 2015-2017 by Guido Vollbeding.
|
||||
* 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 a very simple stand-alone application that inserts
|
||||
* user-supplied text as a COM (comment) marker in a JFIF file.
|
||||
* This may be useful as an example of the minimum logic needed to parse
|
||||
* JPEG markers.
|
||||
*/
|
||||
|
||||
#define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */
|
||||
#include "jinclude.h" /* get auto-config symbols, <stdio.h> */
|
||||
|
||||
#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc() */
|
||||
extern void * malloc ();
|
||||
#endif
|
||||
#include <ctype.h> /* to declare isupper(), tolower() */
|
||||
#ifdef USE_SETMODE
|
||||
#include <fcntl.h> /* to declare setmode()'s parameter macros */
|
||||
/* If you have setmode() but not <io.h>, just delete this line: */
|
||||
#include <io.h> /* to declare setmode() */
|
||||
#endif
|
||||
|
||||
#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
|
||||
#ifdef __MWERKS__
|
||||
#include <SIOUX.h> /* Metrowerks needs this */
|
||||
#include <console.h> /* ... and this */
|
||||
#endif
|
||||
#ifdef THINK_C
|
||||
#include <console.h> /* Think declares it here */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */
|
||||
#define READ_BINARY "r"
|
||||
#define WRITE_BINARY "w"
|
||||
#else
|
||||
#ifdef VMS /* VMS is very nonstandard */
|
||||
#define READ_BINARY "rb", "ctx=stm"
|
||||
#define WRITE_BINARY "wb", "ctx=stm"
|
||||
#else /* standard ANSI-compliant case */
|
||||
#define READ_BINARY "rb"
|
||||
#define WRITE_BINARY "wb"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef EXIT_FAILURE /* define exit() codes if not provided */
|
||||
#define EXIT_FAILURE 1
|
||||
#endif
|
||||
#ifndef EXIT_SUCCESS
|
||||
#ifdef VMS
|
||||
#define EXIT_SUCCESS 1 /* VMS is very nonstandard */
|
||||
#else
|
||||
#define EXIT_SUCCESS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Reduce this value if your malloc() can't allocate blocks up to 64K.
|
||||
* On DOS, compiling in large model is usually a better solution.
|
||||
*/
|
||||
|
||||
#ifndef MAX_COM_LENGTH
|
||||
#define MAX_COM_LENGTH 65000L /* must be <= 65533 in any case */
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* These macros are used to read the input file and write the output file.
|
||||
* To reuse this code in another application, you might need to change these.
|
||||
*/
|
||||
|
||||
static FILE * infile; /* input JPEG file */
|
||||
|
||||
/* Return next input byte, or EOF if no more */
|
||||
#define NEXTBYTE() getc(infile)
|
||||
|
||||
static FILE * outfile; /* output JPEG file */
|
||||
|
||||
/* Emit an output byte */
|
||||
#define PUTBYTE(x) putc((x), outfile)
|
||||
|
||||
|
||||
/* Error exit handler */
|
||||
#define ERREXIT(msg) (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE))
|
||||
|
||||
|
||||
/* Read one byte, testing for EOF */
|
||||
static int
|
||||
read_1_byte (void)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = NEXTBYTE();
|
||||
if (c == EOF)
|
||||
ERREXIT("Premature EOF in JPEG file");
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Read 2 bytes, convert to unsigned int */
|
||||
/* All 2-byte quantities in JPEG markers are MSB first */
|
||||
static unsigned int
|
||||
read_2_bytes (void)
|
||||
{
|
||||
int c1, c2;
|
||||
|
||||
c1 = NEXTBYTE();
|
||||
if (c1 == EOF)
|
||||
ERREXIT("Premature EOF in JPEG file");
|
||||
c2 = NEXTBYTE();
|
||||
if (c2 == EOF)
|
||||
ERREXIT("Premature EOF in JPEG file");
|
||||
return (((unsigned int) c1) << 8) + ((unsigned int) c2);
|
||||
}
|
||||
|
||||
|
||||
/* Routines to write data to output file */
|
||||
|
||||
static void
|
||||
write_1_byte (int c)
|
||||
{
|
||||
PUTBYTE(c);
|
||||
}
|
||||
|
||||
static void
|
||||
write_2_bytes (unsigned int val)
|
||||
{
|
||||
PUTBYTE((val >> 8) & 0xFF);
|
||||
PUTBYTE(val & 0xFF);
|
||||
}
|
||||
|
||||
static void
|
||||
write_marker (int marker)
|
||||
{
|
||||
PUTBYTE(0xFF);
|
||||
PUTBYTE(marker);
|
||||
}
|
||||
|
||||
static void
|
||||
copy_rest_of_file (void)
|
||||
{
|
||||
int c;
|
||||
|
||||
while ((c = NEXTBYTE()) != EOF)
|
||||
PUTBYTE(c);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* JPEG markers consist of one or more 0xFF bytes, followed by a marker
|
||||
* code byte (which is not an FF). Here are the marker codes of interest
|
||||
* in this program. (See jdmarker.c for a more complete list.)
|
||||
*/
|
||||
|
||||
#define M_SOF0 0xC0 /* Start Of Frame N */
|
||||
#define M_SOF1 0xC1 /* N indicates which compression process */
|
||||
#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
|
||||
#define M_SOF3 0xC3
|
||||
#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
|
||||
#define M_SOF6 0xC6
|
||||
#define M_SOF7 0xC7
|
||||
#define M_SOF9 0xC9
|
||||
#define M_SOF10 0xCA
|
||||
#define M_SOF11 0xCB
|
||||
#define M_SOF13 0xCD
|
||||
#define M_SOF14 0xCE
|
||||
#define M_SOF15 0xCF
|
||||
#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */
|
||||
#define M_EOI 0xD9 /* End Of Image (end of datastream) */
|
||||
#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
|
||||
#define M_COM 0xFE /* COMment */
|
||||
|
||||
|
||||
/*
|
||||
* Find the next JPEG marker and return its marker code.
|
||||
* We expect at least one FF byte, possibly more if the compressor used FFs
|
||||
* to pad the file. (Padding FFs will NOT be replicated in the output file.)
|
||||
* There could also be non-FF garbage between markers. The treatment of such
|
||||
* garbage is unspecified; we choose to skip over it but emit a warning msg.
|
||||
* NB: this routine must not be used after seeing SOS marker, since it will
|
||||
* not deal correctly with FF/00 sequences in the compressed image data...
|
||||
*/
|
||||
|
||||
static int
|
||||
next_marker (void)
|
||||
{
|
||||
int c;
|
||||
int discarded_bytes = 0;
|
||||
|
||||
/* Find 0xFF byte; count and skip any non-FFs. */
|
||||
c = read_1_byte();
|
||||
while (c != 0xFF) {
|
||||
discarded_bytes++;
|
||||
c = read_1_byte();
|
||||
}
|
||||
/* Get marker code byte, swallowing any duplicate FF bytes. Extra FFs
|
||||
* are legal as pad bytes, so don't count them in discarded_bytes.
|
||||
*/
|
||||
do {
|
||||
c = read_1_byte();
|
||||
} while (c == 0xFF);
|
||||
|
||||
if (discarded_bytes != 0) {
|
||||
fprintf(stderr, "Warning: garbage data found in JPEG file\n");
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read the initial marker, which should be SOI.
|
||||
* For a JFIF file, the first two bytes of the file should be literally
|
||||
* 0xFF M_SOI. To be more general, we could use next_marker, but if the
|
||||
* input file weren't actually JPEG at all, next_marker might read the whole
|
||||
* file and then return a misleading error message...
|
||||
*/
|
||||
|
||||
static int
|
||||
first_marker (void)
|
||||
{
|
||||
int c1, c2;
|
||||
|
||||
c1 = NEXTBYTE();
|
||||
c2 = NEXTBYTE();
|
||||
if (c1 != 0xFF || c2 != M_SOI)
|
||||
ERREXIT("Not a JPEG file");
|
||||
return c2;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Most types of marker are followed by a variable-length parameter segment.
|
||||
* This routine skips over the parameters for any marker we don't otherwise
|
||||
* want to process.
|
||||
* Note that we MUST skip the parameter segment explicitly in order not to
|
||||
* be fooled by 0xFF bytes that might appear within the parameter segment;
|
||||
* such bytes do NOT introduce new markers.
|
||||
*/
|
||||
|
||||
static void
|
||||
copy_variable (void)
|
||||
/* Copy an unknown or uninteresting variable-length marker */
|
||||
{
|
||||
unsigned int length;
|
||||
|
||||
/* Get the marker parameter length count */
|
||||
length = read_2_bytes();
|
||||
write_2_bytes(length);
|
||||
/* Length includes itself, so must be at least 2 */
|
||||
if (length < 2)
|
||||
ERREXIT("Erroneous JPEG marker length");
|
||||
length -= 2;
|
||||
/* Copy the remaining bytes */
|
||||
while (length > 0) {
|
||||
write_1_byte(read_1_byte());
|
||||
length--;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
skip_variable (void)
|
||||
/* Skip over an unknown or uninteresting variable-length marker */
|
||||
{
|
||||
unsigned int length;
|
||||
|
||||
/* Get the marker parameter length count */
|
||||
length = read_2_bytes();
|
||||
/* Length includes itself, so must be at least 2 */
|
||||
if (length < 2)
|
||||
ERREXIT("Erroneous JPEG marker length");
|
||||
length -= 2;
|
||||
/* Skip over the remaining bytes */
|
||||
while (length > 0) {
|
||||
(void) read_1_byte();
|
||||
length--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse the marker stream until SOFn or EOI is seen;
|
||||
* copy data to output, but discard COM markers unless keep_COM is true.
|
||||
*/
|
||||
|
||||
static int
|
||||
scan_JPEG_header (int keep_COM)
|
||||
{
|
||||
int marker;
|
||||
|
||||
/* Expect SOI at start of file */
|
||||
if (first_marker() != M_SOI)
|
||||
ERREXIT("Expected SOI marker first");
|
||||
write_marker(M_SOI);
|
||||
|
||||
/* Scan miscellaneous markers until we reach SOFn. */
|
||||
for (;;) {
|
||||
marker = next_marker();
|
||||
switch (marker) {
|
||||
/* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be,
|
||||
* treated as SOFn. C4 in particular is actually DHT.
|
||||
*/
|
||||
case M_SOF0: /* Baseline */
|
||||
case M_SOF1: /* Extended sequential, Huffman */
|
||||
case M_SOF2: /* Progressive, Huffman */
|
||||
case M_SOF3: /* Lossless, Huffman */
|
||||
case M_SOF5: /* Differential sequential, Huffman */
|
||||
case M_SOF6: /* Differential progressive, Huffman */
|
||||
case M_SOF7: /* Differential lossless, Huffman */
|
||||
case M_SOF9: /* Extended sequential, arithmetic */
|
||||
case M_SOF10: /* Progressive, arithmetic */
|
||||
case M_SOF11: /* Lossless, arithmetic */
|
||||
case M_SOF13: /* Differential sequential, arithmetic */
|
||||
case M_SOF14: /* Differential progressive, arithmetic */
|
||||
case M_SOF15: /* Differential lossless, arithmetic */
|
||||
return marker;
|
||||
|
||||
case M_SOS: /* should not see compressed data before SOF */
|
||||
ERREXIT("SOS without prior SOFn");
|
||||
break;
|
||||
|
||||
case M_EOI: /* in case it's a tables-only JPEG stream */
|
||||
return marker;
|
||||
|
||||
case M_COM: /* Existing COM: conditionally discard */
|
||||
if (keep_COM) {
|
||||
write_marker(marker);
|
||||
copy_variable();
|
||||
} else {
|
||||
skip_variable();
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* Anything else just gets copied */
|
||||
write_marker(marker);
|
||||
copy_variable(); /* we assume it has a parameter count... */
|
||||
break;
|
||||
}
|
||||
} /* end loop */
|
||||
}
|
||||
|
||||
|
||||
/* Command line parsing code */
|
||||
|
||||
static const char * progname; /* program name for error messages */
|
||||
|
||||
|
||||
static void
|
||||
usage (void)
|
||||
/* complain about bad command line */
|
||||
{
|
||||
fprintf(stderr, "wrjpgcom inserts a textual comment in a JPEG file.\n");
|
||||
fprintf(stderr, "You can add to or replace any existing comment(s).\n");
|
||||
|
||||
fprintf(stderr, "Usage: %s [switches] ", progname);
|
||||
#ifdef TWO_FILE_COMMANDLINE
|
||||
fprintf(stderr, "inputfile outputfile\n");
|
||||
#else
|
||||
fprintf(stderr, "[inputfile]\n");
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "Switches (names may be abbreviated):\n");
|
||||
fprintf(stderr, " -replace Delete any existing comments\n");
|
||||
fprintf(stderr, " -comment \"text\" Insert comment with given text\n");
|
||||
fprintf(stderr, " -cfile name Read comment from named file\n");
|
||||
fprintf(stderr, "Notice that you must put quotes around the comment text\n");
|
||||
fprintf(stderr, "when you use -comment.\n");
|
||||
fprintf(stderr, "If you do not give either -comment or -cfile on the command line,\n");
|
||||
fprintf(stderr, "then the comment text is read from standard input.\n");
|
||||
fprintf(stderr, "It can be multiple lines, up to %u characters total.\n",
|
||||
(unsigned int) MAX_COM_LENGTH);
|
||||
#ifndef TWO_FILE_COMMANDLINE
|
||||
fprintf(stderr, "You must specify an input JPEG file name when supplying\n");
|
||||
fprintf(stderr, "comment text from standard input.\n");
|
||||
#endif
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
keymatch (char * arg, const char * keyword, int minchars)
|
||||
/* Case-insensitive matching of (possibly abbreviated) keyword switches. */
|
||||
/* keyword is the constant keyword (must be lower case already), */
|
||||
/* minchars is length of minimum legal abbreviation. */
|
||||
{
|
||||
register int ca, ck;
|
||||
register int nmatched = 0;
|
||||
|
||||
while ((ca = *arg++) != '\0') {
|
||||
if ((ck = *keyword++) == '\0')
|
||||
return 0; /* arg longer than keyword, no good */
|
||||
if (isupper(ca)) /* force arg to lcase (assume ck is already) */
|
||||
ca = tolower(ca);
|
||||
if (ca != ck)
|
||||
return 0; /* no good */
|
||||
nmatched++; /* count matched characters */
|
||||
}
|
||||
/* reached end of argument; fail if it's too short for unique abbrev */
|
||||
if (nmatched < minchars)
|
||||
return 0;
|
||||
return 1; /* A-OK */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The main program.
|
||||
*/
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int argn;
|
||||
char * arg;
|
||||
int keep_COM = 1;
|
||||
char * comment_arg = NULL;
|
||||
FILE * comment_file = NULL;
|
||||
unsigned int comment_length = 0;
|
||||
int marker;
|
||||
|
||||
/* On Mac, fetch a command line. */
|
||||
#ifdef USE_CCOMMAND
|
||||
argc = ccommand(&argv);
|
||||
#endif
|
||||
|
||||
progname = argv[0];
|
||||
if (progname == NULL || progname[0] == 0)
|
||||
progname = "wrjpgcom"; /* in case C library doesn't provide it */
|
||||
|
||||
/* Parse switches, if any */
|
||||
for (argn = 1; argn < argc; argn++) {
|
||||
arg = argv[argn];
|
||||
if (arg[0] != '-')
|
||||
break; /* not switch, must be file name */
|
||||
arg++; /* advance over '-' */
|
||||
if (keymatch(arg, "replace", 1)) {
|
||||
keep_COM = 0;
|
||||
} else if (keymatch(arg, "cfile", 2)) {
|
||||
if (++argn >= argc) usage();
|
||||
if ((comment_file = fopen(argv[argn], "r")) == NULL) {
|
||||
fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else if (keymatch(arg, "comment", 1)) {
|
||||
if (++argn >= argc) usage();
|
||||
comment_arg = argv[argn];
|
||||
/* If the comment text starts with '"', then we are probably running
|
||||
* under MS-DOG and must parse out the quoted string ourselves. Sigh.
|
||||
*/
|
||||
if (comment_arg[0] == '"') {
|
||||
comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH);
|
||||
if (comment_arg == NULL)
|
||||
ERREXIT("Insufficient memory");
|
||||
if (strlen(argv[argn]+1) >= (size_t) MAX_COM_LENGTH) {
|
||||
fprintf(stderr, "Comment text may not exceed %u bytes\n",
|
||||
(unsigned int) MAX_COM_LENGTH);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
strcpy(comment_arg, argv[argn]+1);
|
||||
for (;;) {
|
||||
comment_length = (unsigned int) strlen(comment_arg);
|
||||
if (comment_length > 0 && comment_arg[comment_length-1] == '"') {
|
||||
comment_arg[comment_length-1] = '\0'; /* zap terminating quote */
|
||||
break;
|
||||
}
|
||||
if (++argn >= argc)
|
||||
ERREXIT("Missing ending quote mark");
|
||||
if (strlen(comment_arg) + 1 + strlen(argv[argn]) >=
|
||||
(size_t) MAX_COM_LENGTH) {
|
||||
fprintf(stderr, "Comment text may not exceed %u bytes\n",
|
||||
(unsigned int) MAX_COM_LENGTH);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
strcat(comment_arg, " ");
|
||||
strcat(comment_arg, argv[argn]);
|
||||
}
|
||||
} else if (strlen(comment_arg) >= (size_t) MAX_COM_LENGTH) {
|
||||
fprintf(stderr, "Comment text may not exceed %u bytes\n",
|
||||
(unsigned int) MAX_COM_LENGTH);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
comment_length = (unsigned int) strlen(comment_arg);
|
||||
} else
|
||||
usage();
|
||||
}
|
||||
|
||||
/* Cannot use both -comment and -cfile. */
|
||||
if (comment_arg != NULL && comment_file != NULL)
|
||||
usage();
|
||||
/* If there is neither -comment nor -cfile, we will read the comment text
|
||||
* from stdin; in this case there MUST be an input JPEG file name.
|
||||
*/
|
||||
if (comment_arg == NULL && comment_file == NULL && argn >= argc)
|
||||
usage();
|
||||
|
||||
/* Open the input file. */
|
||||
if (argn < argc) {
|
||||
if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) {
|
||||
fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
/* default input file is stdin */
|
||||
#ifdef USE_SETMODE /* need to hack file mode? */
|
||||
setmode(fileno(stdin), O_BINARY);
|
||||
#endif
|
||||
#ifdef USE_FDOPEN /* need to re-open in binary mode? */
|
||||
if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
|
||||
fprintf(stderr, "%s: can't open stdin\n", progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#else
|
||||
infile = stdin;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Open the output file. */
|
||||
#ifdef TWO_FILE_COMMANDLINE
|
||||
/* Must have explicit output file name */
|
||||
if (argn != argc-2) {
|
||||
fprintf(stderr, "%s: must name one input and one output file\n",
|
||||
progname);
|
||||
usage();
|
||||
}
|
||||
if ((outfile = fopen(argv[argn+1], WRITE_BINARY)) == NULL) {
|
||||
fprintf(stderr, "%s: can't open %s\n", progname, argv[argn+1]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#else
|
||||
/* Unix style: expect zero or one file name */
|
||||
if (argn < argc-1) {
|
||||
fprintf(stderr, "%s: only one input file\n", progname);
|
||||
usage();
|
||||
}
|
||||
/* default output file is stdout */
|
||||
#ifdef USE_SETMODE /* need to hack file mode? */
|
||||
setmode(fileno(stdout), O_BINARY);
|
||||
#endif
|
||||
#ifdef USE_FDOPEN /* need to re-open in binary mode? */
|
||||
if ((outfile = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) {
|
||||
fprintf(stderr, "%s: can't open stdout\n", progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#else
|
||||
outfile = stdout;
|
||||
#endif
|
||||
#endif /* TWO_FILE_COMMANDLINE */
|
||||
|
||||
/* Collect comment text from comment_file or stdin, if necessary */
|
||||
if (comment_arg == NULL) {
|
||||
FILE * src_file;
|
||||
int c;
|
||||
|
||||
comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH);
|
||||
if (comment_arg == NULL)
|
||||
ERREXIT("Insufficient memory");
|
||||
comment_length = 0;
|
||||
src_file = (comment_file != NULL ? comment_file : stdin);
|
||||
while ((c = getc(src_file)) != EOF) {
|
||||
if (comment_length >= (unsigned int) MAX_COM_LENGTH) {
|
||||
fprintf(stderr, "Comment text may not exceed %u bytes\n",
|
||||
(unsigned int) MAX_COM_LENGTH);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
comment_arg[comment_length++] = (char) c;
|
||||
}
|
||||
if (comment_file != NULL)
|
||||
fclose(comment_file);
|
||||
}
|
||||
|
||||
/* Copy JPEG headers until SOFn marker;
|
||||
* we will insert the new comment marker just before SOFn.
|
||||
* This (a) causes the new comment to appear after, rather than before,
|
||||
* existing comments; and (b) ensures that comments come after any JFIF
|
||||
* or JFXX markers, as required by the JFIF specification.
|
||||
*/
|
||||
marker = scan_JPEG_header(keep_COM);
|
||||
/* Insert the new COM marker, but only if nonempty text has been supplied */
|
||||
if (comment_length > 0) {
|
||||
write_marker(M_COM);
|
||||
write_2_bytes(comment_length + 2);
|
||||
while (comment_length > 0) {
|
||||
write_1_byte(*comment_arg++);
|
||||
comment_length--;
|
||||
}
|
||||
}
|
||||
/* Duplicate the remainder of the source file.
|
||||
* Note that any COM markers occuring after SOF will not be touched.
|
||||
*/
|
||||
write_marker(marker);
|
||||
copy_rest_of_file();
|
||||
|
||||
/* All done. */
|
||||
exit(EXIT_SUCCESS);
|
||||
return 0; /* suppress no-return-value warnings */
|
||||
}
|
||||
|
|
@ -1,264 +0,0 @@
|
|||
/*
|
||||
* wrppm.c
|
||||
*
|
||||
* Copyright (C) 1991-1996, Thomas G. Lane.
|
||||
* Modified 2009-2020 by Guido Vollbeding.
|
||||
* 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 routines to write output images in PPM/PGM format.
|
||||
* The extended 2-byte-per-sample raw PPM/PGM formats are supported.
|
||||
* The PBMPLUS library is NOT required to compile this software
|
||||
* (but it is highly useful as a set of PPM image manipulation programs).
|
||||
*
|
||||
* These routines may need modification for non-Unix environments or
|
||||
* specialized applications. As they stand, they assume output to
|
||||
* an ordinary stdio stream.
|
||||
*/
|
||||
|
||||
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
||||
|
||||
#ifdef PPM_SUPPORTED
|
||||
|
||||
|
||||
/*
|
||||
* For 12-bit JPEG data, we either downscale the values to 8 bits
|
||||
* (to write standard byte-per-sample PPM/PGM files), or output
|
||||
* nonstandard word-per-sample PPM/PGM files. Downscaling is done
|
||||
* if PPM_NORAWWORD is defined (this can be done in the Makefile
|
||||
* or in jconfig.h).
|
||||
* (When the core library supports data precision reduction, a cleaner
|
||||
* implementation will be to ask for that instead.)
|
||||
*/
|
||||
|
||||
#if BITS_IN_JSAMPLE == 8
|
||||
#define PUTPPMSAMPLE(ptr,v) *ptr++ = (char) (v)
|
||||
#define BYTESPERSAMPLE 1
|
||||
#define PPM_MAXVAL 255
|
||||
#else
|
||||
#ifdef PPM_NORAWWORD
|
||||
#define PUTPPMSAMPLE(ptr,v) *ptr++ = (char) ((v) >> (BITS_IN_JSAMPLE-8))
|
||||
#define BYTESPERSAMPLE 1
|
||||
#define PPM_MAXVAL 255
|
||||
#else
|
||||
/* The word-per-sample format always puts the MSB first. */
|
||||
#define PUTPPMSAMPLE(ptr,v) \
|
||||
{ register int val_ = v; \
|
||||
*ptr++ = (char) ((val_ >> 8) & 0xFF); \
|
||||
*ptr++ = (char) (val_ & 0xFF); \
|
||||
}
|
||||
#define BYTESPERSAMPLE 2
|
||||
#define PPM_MAXVAL ((1<<BITS_IN_JSAMPLE)-1)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* When JSAMPLE is the same size as char, we can just fwrite() the
|
||||
* decompressed data to the PPM or PGM file. On PCs, in order to make this
|
||||
* work the output buffer must be allocated in near data space, because we are
|
||||
* assuming small-data memory model wherein fwrite() can't reach far memory.
|
||||
* If you need to process very wide images on a PC, you might have to compile
|
||||
* in large-memory model, or else replace fwrite() with a putc() loop ---
|
||||
* which will be much slower.
|
||||
*/
|
||||
|
||||
|
||||
/* Private version of data destination object */
|
||||
|
||||
typedef struct {
|
||||
struct djpeg_dest_struct pub; /* public fields */
|
||||
|
||||
/* Usually these two pointers point to the same place: */
|
||||
char *iobuffer; /* fwrite's I/O buffer */
|
||||
JSAMPROW pixrow; /* decompressor output buffer */
|
||||
size_t buffer_width; /* width of I/O buffer */
|
||||
JDIMENSION samples_per_row; /* JSAMPLEs per output row */
|
||||
} ppm_dest_struct;
|
||||
|
||||
typedef ppm_dest_struct * ppm_dest_ptr;
|
||||
|
||||
|
||||
/*
|
||||
* Write some pixel data.
|
||||
* In this module rows_supplied will always be 1.
|
||||
*
|
||||
* put_pixel_rows handles the "normal" 8-bit case where the decompressor
|
||||
* output buffer is physically the same as the fwrite buffer.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
|
||||
JDIMENSION rows_supplied)
|
||||
{
|
||||
ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;
|
||||
|
||||
(void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This code is used when we have to copy the data and apply a pixel
|
||||
* format translation. Typically this only happens in 12-bit mode.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
copy_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
|
||||
JDIMENSION rows_supplied)
|
||||
{
|
||||
ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;
|
||||
register char * bufferptr;
|
||||
register JSAMPROW ptr;
|
||||
register JDIMENSION col;
|
||||
|
||||
ptr = dest->pixrow;
|
||||
bufferptr = dest->iobuffer;
|
||||
for (col = dest->samples_per_row; col > 0; col--) {
|
||||
PUTPPMSAMPLE(bufferptr, GETJSAMPLE(*ptr++));
|
||||
}
|
||||
(void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write some pixel data when color quantization is in effect.
|
||||
* We have to demap the color index values to straight data.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
put_demapped_rgb (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
|
||||
JDIMENSION rows_supplied)
|
||||
{
|
||||
ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;
|
||||
register char * bufferptr;
|
||||
register int pixval;
|
||||
register JSAMPROW ptr;
|
||||
register JSAMPROW color_map0 = cinfo->colormap[0];
|
||||
register JSAMPROW color_map1 = cinfo->colormap[1];
|
||||
register JSAMPROW color_map2 = cinfo->colormap[2];
|
||||
register JDIMENSION col;
|
||||
|
||||
ptr = dest->pixrow;
|
||||
bufferptr = dest->iobuffer;
|
||||
for (col = cinfo->output_width; col > 0; col--) {
|
||||
pixval = GETJSAMPLE(*ptr++);
|
||||
PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map0[pixval]));
|
||||
PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map1[pixval]));
|
||||
PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map2[pixval]));
|
||||
}
|
||||
(void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
|
||||
}
|
||||
|
||||
METHODDEF(void)
|
||||
put_demapped_gray (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
|
||||
JDIMENSION rows_supplied)
|
||||
{
|
||||
ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;
|
||||
register char * bufferptr;
|
||||
register JSAMPROW ptr;
|
||||
register JSAMPROW color_map0 = cinfo->colormap[0];
|
||||
register JDIMENSION col;
|
||||
|
||||
ptr = dest->pixrow;
|
||||
bufferptr = dest->iobuffer;
|
||||
for (col = cinfo->output_width; col > 0; col--) {
|
||||
PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map0[GETJSAMPLE(*ptr++)]));
|
||||
}
|
||||
(void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Startup: write the file header.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
start_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
|
||||
{
|
||||
/* Emit file header */
|
||||
switch (cinfo->out_color_space) {
|
||||
case JCS_GRAYSCALE:
|
||||
/* emit header for raw PGM format */
|
||||
fprintf(dinfo->output_file, "P5\n%ld %ld\n%d\n",
|
||||
(long) cinfo->output_width, (long) cinfo->output_height,
|
||||
PPM_MAXVAL);
|
||||
break;
|
||||
case JCS_RGB:
|
||||
/* emit header for raw PPM format */
|
||||
fprintf(dinfo->output_file, "P6\n%ld %ld\n%d\n",
|
||||
(long) cinfo->output_width, (long) cinfo->output_height,
|
||||
PPM_MAXVAL);
|
||||
break;
|
||||
default:
|
||||
ERREXIT(cinfo, JERR_PPM_COLORSPACE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Finish up at the end of the file.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
finish_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
|
||||
{
|
||||
/* Make sure we wrote the output file OK */
|
||||
JFFLUSH(dinfo->output_file);
|
||||
if (JFERROR(dinfo->output_file))
|
||||
ERREXIT(cinfo, JERR_FILE_WRITE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The module selection routine for PPM format output.
|
||||
*/
|
||||
|
||||
GLOBAL(djpeg_dest_ptr)
|
||||
jinit_write_ppm (j_decompress_ptr cinfo)
|
||||
{
|
||||
ppm_dest_ptr dest;
|
||||
|
||||
/* Create module interface object, fill in method pointers */
|
||||
dest = (ppm_dest_ptr) (*cinfo->mem->alloc_small)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(ppm_dest_struct));
|
||||
dest->pub.start_output = start_output_ppm;
|
||||
dest->pub.finish_output = finish_output_ppm;
|
||||
|
||||
/* Calculate output image dimensions so we can allocate space */
|
||||
jpeg_calc_output_dimensions(cinfo);
|
||||
|
||||
/* Create physical I/O buffer. Note we make this near on a PC. */
|
||||
dest->samples_per_row = cinfo->output_width * cinfo->out_color_components;
|
||||
dest->buffer_width = dest->samples_per_row * (BYTESPERSAMPLE * SIZEOF(char));
|
||||
dest->iobuffer = (char *) (*cinfo->mem->alloc_small)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, dest->buffer_width);
|
||||
|
||||
if (cinfo->quantize_colors || BITS_IN_JSAMPLE != 8 ||
|
||||
SIZEOF(JSAMPLE) != SIZEOF(char)) {
|
||||
/* When quantizing, we need an output buffer for colormap indexes
|
||||
* that's separate from the physical I/O buffer. We also need a
|
||||
* separate buffer if pixel format translation must take place.
|
||||
*/
|
||||
dest->pixrow = (JSAMPROW) (*cinfo->mem->alloc_large)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, (size_t) cinfo->output_width *
|
||||
(size_t) cinfo->output_components * SIZEOF(JSAMPLE));
|
||||
if (! cinfo->quantize_colors)
|
||||
dest->pub.put_pixel_rows = copy_pixel_rows;
|
||||
else if (cinfo->out_color_space == JCS_GRAYSCALE)
|
||||
dest->pub.put_pixel_rows = put_demapped_gray;
|
||||
else
|
||||
dest->pub.put_pixel_rows = put_demapped_rgb;
|
||||
} else {
|
||||
/* We will fwrite() directly from decompressor output buffer. */
|
||||
/* Cast here implies near->far pointer conversion on PCs */
|
||||
dest->pixrow = (JSAMPROW) dest->iobuffer;
|
||||
dest->pub.put_pixel_rows = put_pixel_rows;
|
||||
}
|
||||
/* Synthesize a JSAMPARRAY pointer structure */
|
||||
dest->pub.buffer = & dest->pixrow;
|
||||
dest->pub.buffer_height = 1;
|
||||
|
||||
return &dest->pub;
|
||||
}
|
||||
|
||||
#endif /* PPM_SUPPORTED */
|
||||
|
|
@ -1,306 +0,0 @@
|
|||
/*
|
||||
* wrrle.c
|
||||
*
|
||||
* Copyright (C) 1991-1996, Thomas G. Lane.
|
||||
* Modified 2017-2019 by Guido Vollbeding.
|
||||
* 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 routines to write output images in RLE format.
|
||||
* The Utah Raster Toolkit library is required (version 3.1 or later).
|
||||
*
|
||||
* These routines may need modification for non-Unix environments or
|
||||
* specialized applications. As they stand, they assume output to
|
||||
* an ordinary stdio stream.
|
||||
*
|
||||
* Based on code contributed by Mike Lijewski,
|
||||
* with updates from Robert Hutchinson.
|
||||
*/
|
||||
|
||||
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
||||
|
||||
#ifdef RLE_SUPPORTED
|
||||
|
||||
/* rle.h is provided by the Utah Raster Toolkit. */
|
||||
|
||||
#include <rle.h>
|
||||
|
||||
/*
|
||||
* We assume that JSAMPLE has the same representation as rle_pixel,
|
||||
* to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples.
|
||||
*/
|
||||
|
||||
#if BITS_IN_JSAMPLE != 8
|
||||
Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Since RLE stores scanlines bottom-to-top, we have to invert the image
|
||||
* from JPEG's top-to-bottom order. To do this, we save the outgoing data
|
||||
* in a virtual array during put_pixel_row calls, then actually emit the
|
||||
* RLE file during finish_output.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* For now, if we emit an RLE color map then it is always 256 entries long,
|
||||
* though not all of the entries need be used.
|
||||
*/
|
||||
|
||||
#define CMAPBITS 8
|
||||
#define CMAPLENGTH (1<<(CMAPBITS))
|
||||
|
||||
typedef struct {
|
||||
struct djpeg_dest_struct pub; /* public fields */
|
||||
|
||||
jvirt_sarray_ptr image; /* virtual array to store the output image */
|
||||
rle_map *colormap; /* RLE-style color map, or NULL if none */
|
||||
rle_pixel **rle_row; /* To pass rows to rle_putrow() */
|
||||
|
||||
} rle_dest_struct;
|
||||
|
||||
typedef rle_dest_struct * rle_dest_ptr;
|
||||
|
||||
|
||||
/* Forward declarations */
|
||||
METHODDEF(void) rle_put_pixel_rows
|
||||
JPP((j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
|
||||
JDIMENSION rows_supplied));
|
||||
|
||||
|
||||
/*
|
||||
* Write the file header.
|
||||
*
|
||||
* In this module it's easier to wait till finish_output to write anything.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
start_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
|
||||
{
|
||||
rle_dest_ptr dest = (rle_dest_ptr) dinfo;
|
||||
size_t cmapsize;
|
||||
int ci, i;
|
||||
#ifdef PROGRESS_REPORT
|
||||
cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Make sure the image can be stored in RLE format.
|
||||
*
|
||||
* - RLE stores image dimensions as *signed* 16 bit integers. JPEG
|
||||
* uses unsigned, so we have to check the width.
|
||||
*
|
||||
* - Colorspace is expected to be grayscale or RGB.
|
||||
*
|
||||
* - The number of channels (components) is expected to be 1 (grayscale/
|
||||
* pseudocolor) or 3 (truecolor/directcolor).
|
||||
* (could be 2 or 4 if using an alpha channel, but we aren't)
|
||||
*/
|
||||
|
||||
if (cinfo->output_width > 32767 || cinfo->output_height > 32767)
|
||||
ERREXIT2(cinfo, JERR_RLE_DIMENSIONS, cinfo->output_width,
|
||||
cinfo->output_height);
|
||||
|
||||
if (cinfo->out_color_space != JCS_GRAYSCALE &&
|
||||
cinfo->out_color_space != JCS_RGB)
|
||||
ERREXIT(cinfo, JERR_RLE_COLORSPACE);
|
||||
|
||||
if (cinfo->output_components != 1 && cinfo->output_components != 3)
|
||||
ERREXIT1(cinfo, JERR_RLE_TOOMANYCHANNELS, cinfo->num_components);
|
||||
|
||||
/* Convert colormap, if any, to RLE format. */
|
||||
|
||||
dest->colormap = NULL;
|
||||
|
||||
if (cinfo->quantize_colors) {
|
||||
/* Allocate storage for RLE-style cmap, zero any extra entries */
|
||||
cmapsize = cinfo->out_color_components * CMAPLENGTH * SIZEOF(rle_map);
|
||||
dest->colormap = (rle_map *) (*cinfo->mem->alloc_small)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, cmapsize);
|
||||
MEMZERO(dest->colormap, cmapsize);
|
||||
|
||||
/* Save away data in RLE format --- note 8-bit left shift! */
|
||||
/* Shifting would need adjustment for JSAMPLEs wider than 8 bits. */
|
||||
for (ci = 0; ci < cinfo->out_color_components; ci++) {
|
||||
for (i = 0; i < cinfo->actual_number_of_colors; i++) {
|
||||
dest->colormap[ci * CMAPLENGTH + i] =
|
||||
GETJSAMPLE(cinfo->colormap[ci][i]) << 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the output buffer to the first row */
|
||||
dest->pub.buffer = (*cinfo->mem->access_virt_sarray)
|
||||
((j_common_ptr) cinfo, dest->image, (JDIMENSION) 0, (JDIMENSION) 1, TRUE);
|
||||
dest->pub.buffer_height = 1;
|
||||
|
||||
dest->pub.put_pixel_rows = rle_put_pixel_rows;
|
||||
|
||||
#ifdef PROGRESS_REPORT
|
||||
if (progress != NULL) {
|
||||
progress->total_extra_passes++; /* count file writing as separate pass */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write some pixel data.
|
||||
*
|
||||
* This routine just saves the data away in a virtual array.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
rle_put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
|
||||
JDIMENSION rows_supplied)
|
||||
{
|
||||
rle_dest_ptr dest = (rle_dest_ptr) dinfo;
|
||||
|
||||
if (cinfo->output_scanline < cinfo->output_height) {
|
||||
dest->pub.buffer = (*cinfo->mem->access_virt_sarray)
|
||||
((j_common_ptr) cinfo, dest->image,
|
||||
cinfo->output_scanline, (JDIMENSION) 1, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Finish up at the end of the file.
|
||||
*
|
||||
* Here is where we really output the RLE file.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
finish_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
|
||||
{
|
||||
rle_dest_ptr dest = (rle_dest_ptr) dinfo;
|
||||
rle_hdr header; /* Output file information */
|
||||
rle_pixel **rle_row, *red_ptr, *green_ptr, *blue_ptr;
|
||||
JSAMPROW output_row;
|
||||
char cmapcomment[80];
|
||||
int row, col;
|
||||
int ci;
|
||||
#ifdef PROGRESS_REPORT
|
||||
cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
|
||||
#endif
|
||||
|
||||
/* Initialize the header info */
|
||||
header = *rle_hdr_init(NULL);
|
||||
header.rle_file = dest->pub.output_file;
|
||||
header.xmin = 0;
|
||||
header.xmax = cinfo->output_width - 1;
|
||||
header.ymin = 0;
|
||||
header.ymax = cinfo->output_height - 1;
|
||||
header.alpha = 0;
|
||||
header.ncolors = cinfo->output_components;
|
||||
for (ci = 0; ci < cinfo->output_components; ci++) {
|
||||
RLE_SET_BIT(header, ci);
|
||||
}
|
||||
if (cinfo->quantize_colors) {
|
||||
header.ncmap = cinfo->out_color_components;
|
||||
header.cmaplen = CMAPBITS;
|
||||
header.cmap = dest->colormap;
|
||||
/* Add a comment to the output image with the true colormap length. */
|
||||
sprintf(cmapcomment, "color_map_length=%d", cinfo->actual_number_of_colors);
|
||||
rle_putcom(cmapcomment, &header);
|
||||
}
|
||||
|
||||
/* Emit the RLE header and color map (if any) */
|
||||
rle_put_setup(&header);
|
||||
|
||||
/* Now output the RLE data from our virtual array.
|
||||
* We assume here that (a) rle_pixel is represented the same as JSAMPLE,
|
||||
* and (b) we are not on a machine where FAR pointers differ from regular.
|
||||
*/
|
||||
|
||||
#ifdef PROGRESS_REPORT
|
||||
if (progress != NULL) {
|
||||
progress->pub.pass_limit = cinfo->output_height;
|
||||
progress->pub.pass_counter = 0;
|
||||
(*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cinfo->output_components == 1) {
|
||||
for (row = cinfo->output_height - 1; row >= 0; row--) {
|
||||
rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray)
|
||||
((j_common_ptr) cinfo, dest->image,
|
||||
(JDIMENSION) row, (JDIMENSION) 1, FALSE);
|
||||
rle_putrow(rle_row, (int) cinfo->output_width, &header);
|
||||
#ifdef PROGRESS_REPORT
|
||||
if (progress != NULL) {
|
||||
progress->pub.pass_counter++;
|
||||
(*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
for (row = cinfo->output_height - 1; row >= 0; row--) {
|
||||
output_row = * (*cinfo->mem->access_virt_sarray)
|
||||
((j_common_ptr) cinfo, dest->image,
|
||||
(JDIMENSION) row, (JDIMENSION) 1, FALSE);
|
||||
rle_row = dest->rle_row;
|
||||
red_ptr = rle_row[0];
|
||||
green_ptr = rle_row[1];
|
||||
blue_ptr = rle_row[2];
|
||||
for (col = cinfo->output_width; col > 0; col--) {
|
||||
*red_ptr++ = GETJSAMPLE(*output_row++);
|
||||
*green_ptr++ = GETJSAMPLE(*output_row++);
|
||||
*blue_ptr++ = GETJSAMPLE(*output_row++);
|
||||
}
|
||||
rle_putrow(rle_row, (int) cinfo->output_width, &header);
|
||||
#ifdef PROGRESS_REPORT
|
||||
if (progress != NULL) {
|
||||
progress->pub.pass_counter++;
|
||||
(*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PROGRESS_REPORT
|
||||
if (progress != NULL)
|
||||
progress->completed_extra_passes++;
|
||||
#endif
|
||||
|
||||
/* Emit file trailer */
|
||||
rle_puteof(&header);
|
||||
JFFLUSH(dest->pub.output_file);
|
||||
if (JFERROR(dest->pub.output_file))
|
||||
ERREXIT(cinfo, JERR_FILE_WRITE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The module selection routine for RLE format output.
|
||||
*/
|
||||
|
||||
GLOBAL(djpeg_dest_ptr)
|
||||
jinit_write_rle (j_decompress_ptr cinfo)
|
||||
{
|
||||
rle_dest_ptr dest;
|
||||
|
||||
/* Create module interface object, fill in method pointers */
|
||||
dest = (rle_dest_ptr) (*cinfo->mem->alloc_small)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(rle_dest_struct));
|
||||
dest->pub.start_output = start_output_rle;
|
||||
dest->pub.finish_output = finish_output_rle;
|
||||
|
||||
/* Calculate output image dimensions so we can allocate space */
|
||||
jpeg_calc_output_dimensions(cinfo);
|
||||
|
||||
/* Allocate a work array for output to the RLE library. */
|
||||
dest->rle_row = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo,
|
||||
JPOOL_IMAGE, cinfo->output_width, (JDIMENSION) cinfo->output_components);
|
||||
|
||||
/* Allocate a virtual array to hold the image. */
|
||||
dest->image = (*cinfo->mem->request_virt_sarray)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
|
||||
cinfo->output_width * (JDIMENSION) cinfo->output_components,
|
||||
cinfo->output_height, (JDIMENSION) 1);
|
||||
|
||||
return &dest->pub;
|
||||
}
|
||||
|
||||
#endif /* RLE_SUPPORTED */
|
||||
|
|
@ -1,254 +0,0 @@
|
|||
/*
|
||||
* wrtarga.c
|
||||
*
|
||||
* Copyright (C) 1991-1996, Thomas G. Lane.
|
||||
* Modified 2015-2019 by Guido Vollbeding.
|
||||
* 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 routines to write output images in Targa format.
|
||||
*
|
||||
* These routines may need modification for non-Unix environments or
|
||||
* specialized applications. As they stand, they assume output to
|
||||
* an ordinary stdio stream.
|
||||
*
|
||||
* Based on code contributed by Lee Daniel Crocker.
|
||||
*/
|
||||
|
||||
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
|
||||
|
||||
#ifdef TARGA_SUPPORTED
|
||||
|
||||
|
||||
/*
|
||||
* To support 12-bit JPEG data, we'd have to scale output down to 8 bits.
|
||||
* This is not yet implemented.
|
||||
*/
|
||||
|
||||
#if BITS_IN_JSAMPLE != 8
|
||||
Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The output buffer needs to be writable by fwrite(). On PCs, we must
|
||||
* allocate the buffer in near data space, because we are assuming small-data
|
||||
* memory model, wherein fwrite() can't reach far memory. If you need to
|
||||
* process very wide images on a PC, you might have to compile in large-memory
|
||||
* model, or else replace fwrite() with a putc() loop --- which will be much
|
||||
* slower.
|
||||
*/
|
||||
|
||||
|
||||
/* Private version of data destination object */
|
||||
|
||||
typedef struct {
|
||||
struct djpeg_dest_struct pub; /* public fields */
|
||||
|
||||
char *iobuffer; /* physical I/O buffer */
|
||||
JDIMENSION buffer_width; /* width of one row */
|
||||
} tga_dest_struct;
|
||||
|
||||
typedef tga_dest_struct * tga_dest_ptr;
|
||||
|
||||
|
||||
LOCAL(void)
|
||||
write_header (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, int num_colors)
|
||||
/* Create and write a Targa header */
|
||||
{
|
||||
char targaheader[18];
|
||||
|
||||
/* Set unused fields of header to 0 */
|
||||
MEMZERO(targaheader, SIZEOF(targaheader));
|
||||
|
||||
if (num_colors > 0) {
|
||||
targaheader[1] = 1; /* color map type 1 */
|
||||
targaheader[5] = (char) (num_colors & 0xFF);
|
||||
targaheader[6] = (char) (num_colors >> 8);
|
||||
targaheader[7] = 24; /* 24 bits per cmap entry */
|
||||
}
|
||||
|
||||
targaheader[12] = (char) (cinfo->output_width & 0xFF);
|
||||
targaheader[13] = (char) (cinfo->output_width >> 8);
|
||||
targaheader[14] = (char) (cinfo->output_height & 0xFF);
|
||||
targaheader[15] = (char) (cinfo->output_height >> 8);
|
||||
targaheader[17] = 0x20; /* Top-down, non-interlaced */
|
||||
|
||||
if (cinfo->out_color_space == JCS_GRAYSCALE) {
|
||||
targaheader[2] = 3; /* image type = uncompressed grayscale */
|
||||
targaheader[16] = 8; /* bits per pixel */
|
||||
} else { /* must be RGB */
|
||||
if (num_colors > 0) {
|
||||
targaheader[2] = 1; /* image type = colormapped RGB */
|
||||
targaheader[16] = 8;
|
||||
} else {
|
||||
targaheader[2] = 2; /* image type = uncompressed RGB */
|
||||
targaheader[16] = 24;
|
||||
}
|
||||
}
|
||||
|
||||
if (JFWRITE(dinfo->output_file, targaheader, 18) != (size_t) 18)
|
||||
ERREXIT(cinfo, JERR_FILE_WRITE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write some pixel data.
|
||||
* In this module rows_supplied will always be 1.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
|
||||
JDIMENSION rows_supplied)
|
||||
/* used for unquantized full-color output */
|
||||
{
|
||||
tga_dest_ptr dest = (tga_dest_ptr) dinfo;
|
||||
register JSAMPROW inptr;
|
||||
register char * outptr;
|
||||
register JDIMENSION col;
|
||||
|
||||
inptr = dest->pub.buffer[0];
|
||||
outptr = dest->iobuffer;
|
||||
for (col = cinfo->output_width; col > 0; col--) {
|
||||
outptr[0] = (char) GETJSAMPLE(inptr[2]); /* RGB to BGR order */
|
||||
outptr[1] = (char) GETJSAMPLE(inptr[1]);
|
||||
outptr[2] = (char) GETJSAMPLE(inptr[0]);
|
||||
inptr += 3, outptr += 3;
|
||||
}
|
||||
(void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
|
||||
}
|
||||
|
||||
METHODDEF(void)
|
||||
put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
|
||||
JDIMENSION rows_supplied)
|
||||
/* used for grayscale OR quantized color output */
|
||||
{
|
||||
tga_dest_ptr dest = (tga_dest_ptr) dinfo;
|
||||
register JSAMPROW inptr;
|
||||
register char * outptr;
|
||||
register JDIMENSION col;
|
||||
|
||||
inptr = dest->pub.buffer[0];
|
||||
outptr = dest->iobuffer;
|
||||
for (col = cinfo->output_width; col > 0; col--) {
|
||||
*outptr++ = (char) GETJSAMPLE(*inptr++);
|
||||
}
|
||||
(void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write some demapped pixel data when color quantization is in effect.
|
||||
* For Targa, this is only applied to grayscale data.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
put_demapped_gray (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
|
||||
JDIMENSION rows_supplied)
|
||||
{
|
||||
tga_dest_ptr dest = (tga_dest_ptr) dinfo;
|
||||
register JSAMPROW inptr;
|
||||
register char * outptr;
|
||||
register JSAMPROW color_map0 = cinfo->colormap[0];
|
||||
register JDIMENSION col;
|
||||
|
||||
inptr = dest->pub.buffer[0];
|
||||
outptr = dest->iobuffer;
|
||||
for (col = cinfo->output_width; col > 0; col--) {
|
||||
*outptr++ = (char) GETJSAMPLE(color_map0[GETJSAMPLE(*inptr++)]);
|
||||
}
|
||||
(void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Startup: write the file header.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
start_output_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
|
||||
{
|
||||
int num_colors, i;
|
||||
FILE *outfile;
|
||||
|
||||
switch (cinfo->out_color_space) {
|
||||
case JCS_GRAYSCALE:
|
||||
/* Targa doesn't have a mapped grayscale format, so we will */
|
||||
/* demap quantized gray output. Never emit a colormap. */
|
||||
write_header(cinfo, dinfo, 0);
|
||||
if (cinfo->quantize_colors)
|
||||
dinfo->put_pixel_rows = put_demapped_gray;
|
||||
else
|
||||
dinfo->put_pixel_rows = put_gray_rows;
|
||||
break;
|
||||
case JCS_RGB:
|
||||
if (cinfo->quantize_colors) {
|
||||
/* We only support 8-bit colormap indexes, so only 256 colors */
|
||||
num_colors = cinfo->actual_number_of_colors;
|
||||
if (num_colors > 256)
|
||||
ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, num_colors);
|
||||
write_header(cinfo, dinfo, num_colors);
|
||||
/* Write the colormap. Note Targa uses BGR byte order */
|
||||
outfile = dinfo->output_file;
|
||||
for (i = 0; i < num_colors; i++) {
|
||||
putc(GETJSAMPLE(cinfo->colormap[2][i]), outfile);
|
||||
putc(GETJSAMPLE(cinfo->colormap[1][i]), outfile);
|
||||
putc(GETJSAMPLE(cinfo->colormap[0][i]), outfile);
|
||||
}
|
||||
dinfo->put_pixel_rows = put_gray_rows;
|
||||
} else {
|
||||
write_header(cinfo, dinfo, 0);
|
||||
dinfo->put_pixel_rows = put_pixel_rows;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERREXIT(cinfo, JERR_TGA_COLORSPACE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Finish up at the end of the file.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
finish_output_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
|
||||
{
|
||||
/* Make sure we wrote the output file OK */
|
||||
JFFLUSH(dinfo->output_file);
|
||||
if (JFERROR(dinfo->output_file))
|
||||
ERREXIT(cinfo, JERR_FILE_WRITE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The module selection routine for Targa format output.
|
||||
*/
|
||||
|
||||
GLOBAL(djpeg_dest_ptr)
|
||||
jinit_write_targa (j_decompress_ptr cinfo)
|
||||
{
|
||||
tga_dest_ptr dest;
|
||||
|
||||
/* Create module interface object, fill in method pointers */
|
||||
dest = (tga_dest_ptr) (*cinfo->mem->alloc_small)
|
||||
((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(tga_dest_struct));
|
||||
dest->pub.start_output = start_output_tga;
|
||||
dest->pub.finish_output = finish_output_tga;
|
||||
|
||||
/* Calculate output image dimensions so we can allocate space */
|
||||
jpeg_calc_output_dimensions(cinfo);
|
||||
|
||||
/* Create I/O buffer. Note we make this near on a PC. */
|
||||
dest->buffer_width = cinfo->output_width * cinfo->output_components;
|
||||
dest->iobuffer = (char *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,
|
||||
JPOOL_IMAGE, (size_t) dest->buffer_width * SIZEOF(char));
|
||||
|
||||
/* Create decompressor output buffer. */
|
||||
dest->pub.buffer = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo,
|
||||
JPOOL_IMAGE, dest->buffer_width, (JDIMENSION) 1);
|
||||
dest->pub.buffer_height = 1;
|
||||
|
||||
return &dest->pub;
|
||||
}
|
||||
|
||||
#endif /* TARGA_SUPPORTED */
|
||||
|
|
@ -9,15 +9,10 @@ CODE="${ROOT}/code"
|
|||
prepare()
|
||||
{
|
||||
local URL="$1"
|
||||
shift
|
||||
local EXCLUDE_PATTERNS=("$@")
|
||||
local INCLUDE_PATTERN="$2"
|
||||
local EXCLUDE_PATTERN="$3"
|
||||
local FILENAME=$(basename ${URL})
|
||||
|
||||
local EXCLUDE_ARGS=
|
||||
for EXCLUDE_PATTERN in "${EXCLUDE_PATTERNS[@]}"; do
|
||||
EXCLUDE_ARGS+=" -not -regex ${EXCLUDE_PATTERN}"
|
||||
done
|
||||
|
||||
echo ${FILENAME}
|
||||
|
||||
local EXTRACT_LOG=$(mktemp)
|
||||
|
|
@ -27,7 +22,8 @@ prepare()
|
|||
(
|
||||
cd ${CODE}/${DIR}
|
||||
[ -f ./configure ] && ./configure
|
||||
find . -type f ${EXCLUDE_ARGS[@]} -delete
|
||||
find . -type f -not -regex ${INCLUDE_PATTERN} -delete
|
||||
find . -type f -regex ${EXCLUDE_PATTERN} -delete
|
||||
find . -type d -empty -delete
|
||||
)
|
||||
}
|
||||
|
|
@ -37,4 +33,4 @@ prepare "https://downloads.xiph.org/releases/vorbis/libvorbis-1.3.7.tar.gz" "\./
|
|||
prepare "https://downloads.xiph.org/releases/opus/opus-1.5.2.tar.gz" "\./\(celt\|include\|silk\|src\)/.*\.[ch]"
|
||||
prepare "https://downloads.xiph.org/releases/opus/opusfile-0.12.tar.gz" "\./\(include\|src\)/.*\.[ch]"
|
||||
prepare "https://zlib.net/zlib-1.3.1.tar.gz" "./[^/]*\.[ch]"
|
||||
prepare "https://www.ijg.org/files/jpegsrc.v9f.tar.gz" "./[^/]*\.[ch]"
|
||||
prepare "https://www.ijg.org/files/jpegsrc.v9f.tar.gz" "./\(j.*\.c\|.*\.h\)" "./jmem\(ansi\|dos\|mac\|name\)\.c"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user