/*
* jpegtran.c
*
- * Copyright (C) 1995-2001, Thomas G. Lane.
+ * Copyright (C) 1995-2010, Thomas G. Lane, 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 JPEG transcoding.
- * It is very similar to cjpeg.c, but provides lossless transcoding between
- * different JPEG file formats. It also provides some lossless and sort-of-
- * lossless transformations of JPEG data.
+ * It is very similar to cjpeg.c, and partly to djpeg.c, but provides
+ * lossless transcoding between different JPEG file formats. It also
+ * provides some lossless and sort-of-lossless transformations of JPEG data.
*/
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
static const char * progname; /* program name for error messages */
static char * outfilename; /* for -outfile switch */
-static char * dropfilename; /* for -drop switch */
+static char * scaleoption; /* -scale switch */
static JCOPY_OPTION copyoption; /* -copy switch */
static jpeg_transform_info transformoption; /* image transformation options */
fprintf(stderr, " -copy none Copy no extra markers from source file\n");
fprintf(stderr, " -copy comments Copy only comment markers (default)\n");
fprintf(stderr, " -copy all Copy all extra markers\n");
- fprintf(stderr, " -copy exif Copy EXIF marker and omit JFIF if EXIF\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
-#if TRANSFORMS_SUPPORTED
fprintf(stderr, "Switches for modifying the image:\n");
+#if TRANSFORMS_SUPPORTED
fprintf(stderr, " -crop WxH+X+Y Crop to a rectangular subarea\n");
- fprintf(stderr, " -drop +X+Y filename Drop another image\n");
fprintf(stderr, " -grayscale Reduce to grayscale (omit color data)\n");
fprintf(stderr, " -flip [horizontal|vertical] Mirror image (left-right or top-bottom)\n");
fprintf(stderr, " -perfect Fail if there is non-transformable edge blocks\n");
fprintf(stderr, " -rotate [90|180|270] Rotate image (degrees clockwise)\n");
+#endif
+ fprintf(stderr, " -scale M/N Scale output image by fraction M/N, eg, 1/8\n");
+#if TRANSFORMS_SUPPORTED
fprintf(stderr, " -transpose Transpose image\n");
fprintf(stderr, " -transverse Transverse transpose image\n");
- fprintf(stderr, " -trim Drop non-transformable edge blocks or\n");
- fprintf(stderr, " with -drop: Requantize drop file to source file\n");
-#endif /* TRANSFORMS_SUPPORTED */
+ fprintf(stderr, " -trim Drop non-transformable edge blocks\n");
+#endif
fprintf(stderr, "Switches for advanced users:\n");
fprintf(stderr, " -restart N Set restart interval in rows, or in blocks with B\n");
fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n");
#endif
}
-LOCAL(void)
-handle_exif (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- JCOPY_OPTION *copyoption)
-/* Adjust the marker writing options to create an EXIF file, instead of JFIF,
- * if so requested or an EXIF file is detected as input. Must be called after
- * jpeg_copy_critical_parameters() as that sets the defaults. */
-{
- jpeg_saved_marker_ptr cur_marker, prev_marker;
-
- /* Look for an exif marker */
- prev_marker = NULL;
- cur_marker = srcinfo->marker_list;
- while (cur_marker != NULL) {
- if (cur_marker->marker == JPEG_APP0+1 &&
- cur_marker->data_length >= 6 &&
- GETJOCTET(cur_marker->data[0]) == 0x45 &&
- GETJOCTET(cur_marker->data[1]) == 0x78 &&
- GETJOCTET(cur_marker->data[2]) == 0x69 &&
- GETJOCTET(cur_marker->data[3]) == 0x66 &&
- GETJOCTET(cur_marker->data[4]) == 0 &&
- GETJOCTET(cur_marker->data[5]) == 0)
- break; /* found an EXIF marker */
- prev_marker = cur_marker;
- cur_marker = cur_marker->next;
- }
- /* If we've found an EXIF marker but not JFIF this is an EXIF file. Unless
- * explicitely requested, make sure we keep the EXIF marker and do not
- * emit a JFIF marker (which would come before). EXIF requires that the
- * first marker be EXIF. */
- if (cur_marker != NULL &&
- ((*copyoption != JCOPYOPT_NONE && !srcinfo->saw_JFIF_marker) ||
- (*copyoption == JCOPYOPT_EXIF))) {
- dstinfo->write_JFIF_header = FALSE;
- if (*copyoption == JCOPYOPT_COMMENTS)
- *copyoption = JCOPYOPT_EXIF;
- }
- /* If making an EXIF file, make sure that EXIF is first marker */
- if (cur_marker != NULL && prev_marker != NULL &&
- *copyoption == JCOPYOPT_EXIF) {
- prev_marker->next = cur_marker->next;
- cur_marker->next = srcinfo->marker_list;
- srcinfo->marker_list = cur_marker;
- }
-}
LOCAL(int)
parse_switches (j_compress_ptr cinfo, int argc, char **argv,
/* Set up default JPEG parameters. */
simple_progressive = FALSE;
outfilename = NULL;
- dropfilename = NULL;
+ scaleoption = NULL;
copyoption = JCOPYOPT_DEFAULT;
transformoption.transform = JXFORM_NONE;
- transformoption.trim = FALSE;
transformoption.perfect = FALSE;
+ transformoption.trim = FALSE;
transformoption.force_grayscale = FALSE;
transformoption.crop = FALSE;
cinfo->err->trace_level = 0;
copyoption = JCOPYOPT_COMMENTS;
} else if (keymatch(argv[argn], "all", 1)) {
copyoption = JCOPYOPT_ALL;
- } else if (keymatch(argv[argn], "exif", 1)) {
- copyoption = JCOPYOPT_EXIF;
} else
usage();
#if TRANSFORMS_SUPPORTED
if (++argn >= argc) /* advance to next argument */
usage();
- if (transformoption.crop /* reject multiple crop/drop requests */ ||
- ! jtransform_parse_crop_spec(&transformoption, argv[argn])) {
+ if (! jtransform_parse_crop_spec(&transformoption, argv[argn])) {
fprintf(stderr, "%s: bogus -crop argument '%s'\n",
progname, argv[argn]);
exit(EXIT_FAILURE);
select_transform(JXFORM_NONE); /* force an error */
#endif
- } else if (keymatch(arg, "drop", 2)) {
-#if TRANSFORMS_SUPPORTED
- if (++argn >= argc) /* advance to next argument */
- usage();
- if (transformoption.crop /* reject multiple crop/drop requests */ ||
- ! jtransform_parse_crop_spec(&transformoption, argv[argn]) ||
- transformoption.crop_width_set != JCROP_UNSET ||
- transformoption.crop_height_set != JCROP_UNSET) {
- fprintf(stderr, "%s: bogus -drop argument '%s'\n",
- progname, argv[argn]);
- exit(EXIT_FAILURE);
- }
- if (++argn >= argc) /* advance to next argument */
- usage();
- dropfilename = argv[argn];
- select_transform(JXFORM_DROP);
-#else
- select_transform(JXFORM_NONE); /* force an error */
-#endif
-
-
} else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
/* Enable debug printouts. */
/* On first -d, print version identification */
if (! printed_version) {
fprintf(stderr, "Independent JPEG Group's JPEGTRAN, version %s\n%s\n",
JVERSION, JCOPYRIGHT);
- fprintf(stderr, "EXIF support v 0.1 added 29-Sep-2003\n");
printed_version = TRUE;
}
cinfo->err->trace_level++;
else
usage();
+ } else if (keymatch(arg, "scale", 4)) {
+ /* Scale the output image by a fraction M/N. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ scaleoption = argv[argn];
+ /* We must postpone processing until decompression startup. */
+
} else if (keymatch(arg, "scans", 1)) {
/* Set scan script. */
#ifdef C_MULTISCAN_FILES_SUPPORTED
main (int argc, char **argv)
{
struct jpeg_decompress_struct srcinfo;
- struct jpeg_error_mgr jsrcerr;
-#if TRANSFORMS_SUPPORTED
- struct jpeg_decompress_struct dropinfo;
- struct jpeg_error_mgr jdroperr;
- FILE * drop_file;
-#endif
struct jpeg_compress_struct dstinfo;
- struct jpeg_error_mgr jdsterr;
+ struct jpeg_error_mgr jsrcerr, jdsterr;
#ifdef PROGRESS_REPORT
struct cdjpeg_progress_mgr progress;
#endif
/* default input file is stdin */
fp = read_stdin();
}
-#if TRANSFORMS_SUPPORTED
- /* Open the drop file. */
- if (dropfilename != NULL) {
- if ((drop_file = fopen(dropfilename, READ_BINARY)) == NULL) {
- fprintf(stderr, "%s: can't open %s for reading\n", progname, dropfilename);
- exit(EXIT_FAILURE);
- }
- dropinfo.err = jpeg_std_error(&jdroperr);
- jpeg_create_decompress(&dropinfo);
- jpeg_stdio_src(&dropinfo, drop_file);
- } else {
- drop_file = NULL;
- }
-#endif
-
#ifdef PROGRESS_REPORT
start_progress_monitor((j_common_ptr) &dstinfo, &progress);
/* Read file header */
(void) jpeg_read_header(&srcinfo, TRUE);
-#if TRANSFORMS_SUPPORTED
- if (dropfilename != NULL) {
- (void) jpeg_read_header(&dropinfo, TRUE);
- transformoption.crop_width = dropinfo.image_width;
- transformoption.crop_width_set = JCROP_POS;
- transformoption.crop_height = dropinfo.image_height;
- transformoption.crop_height_set = JCROP_POS;
- transformoption.drop_ptr = &dropinfo;
- }
-#endif
+ /* Adjust default decompression parameters */
+ if (scaleoption != NULL)
+ if (sscanf(scaleoption, "%d/%d",
+ &srcinfo.scale_num, &srcinfo.scale_denom) < 1)
+ usage();
/* Any space needed by a transform option must be requested before
* jpeg_read_coefficients so that memory allocation will be done right.
*/
#if TRANSFORMS_SUPPORTED
- /* Fails right away if -perfect is given and transformation is not perfect.
+ /* Fail right away if -perfect is given and transformation is not perfect.
*/
- if (transformoption.perfect &&
- !jtransform_perfect_transform(srcinfo.image_width, srcinfo.image_height,
- srcinfo.max_h_samp_factor * DCTSIZE, srcinfo.max_v_samp_factor * DCTSIZE,
- transformoption.transform)) {
+ if (!jtransform_request_workspace(&srcinfo, &transformoption)) {
fprintf(stderr, "%s: transformation is not perfect\n", progname);
exit(EXIT_FAILURE);
}
- jtransform_request_workspace(&srcinfo, &transformoption);
#endif
/* Read source file as DCT coefficients */
src_coef_arrays = jpeg_read_coefficients(&srcinfo);
-#if TRANSFORMS_SUPPORTED
- if (dropfilename != NULL) {
- transformoption.drop_coef_arrays = jpeg_read_coefficients(&dropinfo);
- }
-#endif
-
/* Initialize destination compression parameters from source values */
jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
-
/* Adjust destination parameters if required by transform options;
* also find out which set of coefficient arrays will hold the output.
*/
}
/* Adjust default compression parameters by re-parsing the options */
- /* Save value of copyoption */
file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE);
- /* If we want EXIF, make sure we do not write incompatible markers */
- handle_exif(&srcinfo,&dstinfo,©option);
-
/* Specify data destination for compression */
jpeg_stdio_dest(&dstinfo, fp);
/* Execute image transformation, if any */
#if TRANSFORMS_SUPPORTED
- jtransform_execute_transform(&srcinfo, &dstinfo,
- src_coef_arrays,
- &transformoption);
+ jtransform_execute_transformation(&srcinfo, &dstinfo,
+ src_coef_arrays,
+ &transformoption);
#endif
/* Finish compression and release memory */
jpeg_finish_compress(&dstinfo);
jpeg_destroy_compress(&dstinfo);
-#if TRANSFORMS_SUPPORTED
- if (dropfilename != NULL) {
- (void) jpeg_finish_decompress(&dropinfo);
- jpeg_destroy_decompress(&dropinfo);
- }
-#endif
(void) jpeg_finish_decompress(&srcinfo);
jpeg_destroy_decompress(&srcinfo);
/* Close output file, if we opened it */
if (fp != stdout)
fclose(fp);
-#if TRANSFORMS_SUPPORTED
- if (drop_file != NULL)
- fclose(drop_file);
-#endif
#ifdef PROGRESS_REPORT
end_progress_monitor((j_common_ptr) &dstinfo);
#endif
/* All done. */
-#if TRANSFORMS_SUPPORTED
- if (dropfilename != NULL)
- exit(jsrcerr.num_warnings + jdroperr.num_warnings + jdsterr.num_warnings ?
- EXIT_WARNING : EXIT_SUCCESS);
-#endif
exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS);
return 0; /* suppress no-return-value warnings */
}