Imported Upstream version 1.5.3
[platform/upstream/libjpeg-turbo.git] / cjpeg.c
diff --git a/cjpeg.c b/cjpeg.c
index 0475c02..9d282b8 100644 (file)
--- a/cjpeg.c
+++ b/cjpeg.c
@@ -1,19 +1,21 @@
 /*
  * cjpeg.c
  *
+ * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-1998, Thomas G. Lane.
- * Modified 2003-2008 by Guido Vollbeding.
- * Copyright (C) 2010, D. R. Commander.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
+ * Modified 2003-2011 by Guido Vollbeding.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2010, 2013-2014, 2017, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * 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]
+ *      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).
  * 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
+ *      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 */
-#include "config.h"
+#include "cdjpeg.h"             /* Common decls for cjpeg/djpeg applications */
+#include "jversion.h"           /* for version message */
+#include "jconfigint.h"
 
-#ifdef USE_CCOMMAND            /* command-line reader for Macintosh */
+#ifdef USE_CCOMMAND             /* command-line reader for Macintosh */
 #ifdef __MWERKS__
 #include <SIOUX.h>              /* Metrowerks needs this */
-#include <console.h>           /* ... and this */
+#include <console.h>            /* ... and this */
 #endif
 #ifdef THINK_C
-#include <console.h>           /* Think declares it here */
+#include <console.h>            /* Think declares it here */
 #endif
 #endif
 
 
 /* Create the add-on message string table. */
 
-#define JMESSAGE(code,string)  string ,
+#define JMESSAGE(code,string)   string ,
 
 static const char * const cdjpeg_message_table[] = {
 #include "cderror.h"
@@ -76,11 +78,11 @@ static const char * const cdjpeg_message_table[] = {
  * seldom-used ID field), so we provide a switch to force Targa input mode.
  */
 
-static boolean is_targa;       /* records user -targa switch */
+static boolean is_targa;        /* records user -targa switch */
 
 
 LOCAL(cjpeg_source_ptr)
-select_file_type (j_compress_ptr cinfo, FILE * infile)
+select_file_type (j_compress_ptr cinfo, FILE *infile)
 {
   int c;
 
@@ -123,7 +125,7 @@ select_file_type (j_compress_ptr cinfo, FILE * infile)
     break;
   }
 
-  return NULL;                 /* suppress compiler warnings */
+  return NULL;                  /* suppress compiler warnings */
 }
 
 
@@ -136,8 +138,9 @@ select_file_type (j_compress_ptr cinfo, FILE * infile)
  */
 
 
-static const char * progname;  /* program name for error messages */
-static char * outfilename;     /* for -outfile switch */
+static const char *progname;    /* program name for error messages */
+static char *outfilename;       /* for -outfile switch */
+boolean memdst;                 /* for -memdst switch */
 
 
 LOCAL(void)
@@ -152,8 +155,10 @@ usage (void)
 #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, "  -quality N[,...]   Compression quality (0..100; 5-95 is most useful range,\n");
+  fprintf(stderr, "                     default is 75)\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
@@ -169,15 +174,15 @@ usage (void)
 #endif
 #ifdef DCT_ISLOW_SUPPORTED
   fprintf(stderr, "  -dct int       Use integer DCT method%s\n",
-         (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : ""));
+          (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)" : ""));
+          (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)" : ""));
+          (JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : ""));
 #endif
   fprintf(stderr, "  -restart N     Set restart interval in rows, or in blocks with B\n");
 #ifdef INPUT_SMOOTHING_SUPPORTED
@@ -185,14 +190,18 @@ usage (void)
 #endif
   fprintf(stderr, "  -maxmemory N   Maximum memory to use (in kbytes)\n");
   fprintf(stderr, "  -outfile name  Specify name for output file\n");
+#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
+  fprintf(stderr, "  -memdst        Compress to memory instead of file (useful for benchmarking)\n");
+#endif
   fprintf(stderr, "  -verbose  or  -debug   Emit debug output\n");
+  fprintf(stderr, "  -version       Print version information and exit\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, "  -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");
+  fprintf(stderr, "  -scans FILE    Create multi-scan JPEG per script FILE\n");
 #endif
   exit(EXIT_FAILURE);
 }
@@ -200,7 +209,7 @@ usage (void)
 
 LOCAL(int)
 parse_switches (j_compress_ptr cinfo, int argc, char **argv,
-               int last_file_arg_seen, boolean for_real)
+                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;
@@ -211,21 +220,22 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
  */
 {
   int argn;
-  char * arg;
+  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 */
+  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 */
+  force_baseline = FALSE;       /* by default, allow 16-bit quantizers */
   simple_progressive = FALSE;
   is_targa = FALSE;
   outfilename = NULL;
+  memdst = FALSE;
   cinfo->err->trace_level = 0;
 
   /* Scan command line options, adjust parameters */
@@ -235,12 +245,12 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
     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 */
+        outfilename = NULL;     /* -outfile applies to just one input file */
+        continue;               /* ignore this name if previously processed */
       }
-      break;                   /* else done parsing switches */
+      break;                    /* else done parsing switches */
     }
-    arg++;                     /* advance past switch marker character */
+    arg++;                      /* advance past switch marker character */
 
     if (keymatch(arg, "arithmetic", 1)) {
       /* Use arithmetic coding. */
@@ -248,7 +258,7 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
       cinfo->arith_code = TRUE;
 #else
       fprintf(stderr, "%s: sorry, arithmetic coding not supported\n",
-             progname);
+              progname);
       exit(EXIT_FAILURE);
 #endif
 
@@ -258,16 +268,16 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
 
     } else if (keymatch(arg, "dct", 2)) {
       /* Select DCT algorithm. */
-      if (++argn >= argc)      /* advance to next argument */
-       usage();
+      if (++argn >= argc)       /* advance to next argument */
+        usage();
       if (keymatch(argv[argn], "int", 1)) {
-       cinfo->dct_method = JDCT_ISLOW;
+        cinfo->dct_method = JDCT_ISLOW;
       } else if (keymatch(argv[argn], "fast", 2)) {
-       cinfo->dct_method = JDCT_IFAST;
+        cinfo->dct_method = JDCT_IFAST;
       } else if (keymatch(argv[argn], "float", 2)) {
-       cinfo->dct_method = JDCT_FLOAT;
+        cinfo->dct_method = JDCT_FLOAT;
       } else
-       usage();
+        usage();
 
     } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
       /* Enable debug printouts. */
@@ -275,30 +285,39 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
       static boolean printed_version = FALSE;
 
       if (! printed_version) {
-       fprintf(stderr, "%s version %s (build %s)\n",
-               PACKAGE_NAME, VERSION, BUILD);
-       fprintf(stderr, "%s\n\n", JCOPYRIGHT);
-       fprintf(stderr, "Emulating The Independent JPEG Group's libjpeg, version %s\n\n",
-               JVERSION);
-       printed_version = TRUE;
+        fprintf(stderr, "%s version %s (build %s)\n",
+                PACKAGE_NAME, VERSION, BUILD);
+        fprintf(stderr, "%s\n\n", JCOPYRIGHT);
+        fprintf(stderr, "Emulating The Independent JPEG Group's software, version %s\n\n",
+                JVERSION);
+        printed_version = TRUE;
       }
       cinfo->err->trace_level++;
 
+    } else if (keymatch(arg, "version", 4)) {
+      fprintf(stderr, "%s version %s (build %s)\n",
+              PACKAGE_NAME, VERSION, BUILD);
+      exit(EXIT_SUCCESS);
+
     } 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)) {
+      /* Force an RGB JPEG file to be generated. */
+      jpeg_set_colorspace(cinfo, JCS_RGB);
+
     } 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 (++argn >= argc)       /* advance to next argument */
+        usage();
       if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
-       usage();
+        usage();
       if (ch == 'm' || ch == 'M')
-       lval *= 1000L;
+        lval *= 1000L;
       cinfo->mem->max_memory_to_use = lval * 1000L;
 
     } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) {
@@ -306,16 +325,16 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
 #ifdef ENTROPY_OPT_SUPPORTED
       cinfo->optimize_coding = TRUE;
 #else
-      fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n",
-             progname);
+      fprintf(stderr, "%s: sorry, entropy optimization was not compiled in\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 */
+      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. */
@@ -323,21 +342,31 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
       simple_progressive = TRUE;
       /* We must postpone execution until num_components is known. */
 #else
-      fprintf(stderr, "%s: sorry, progressive output was not compiled\n",
-             progname);
+      fprintf(stderr, "%s: sorry, progressive output was not compiled in\n",
+              progname);
+      exit(EXIT_FAILURE);
+#endif
+
+    } else if (keymatch(arg, "memdst", 2)) {
+      /* Use in-memory destination manager */
+#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
+      memdst = TRUE;
+#else
+      fprintf(stderr, "%s: sorry, in-memory destination manager was not compiled in\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();
+      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();
+      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
@@ -346,8 +375,8 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
 
     } else if (keymatch(arg, "qtables", 2)) {
       /* Quantization tables fetched from file. */
-      if (++argn >= argc)      /* advance to next argument */
-       usage();
+      if (++argn >= argc)       /* advance to next argument */
+        usage();
       qtablefile = argv[argn];
       /* We postpone actually reading the file in case -quality comes later. */
 
@@ -356,24 +385,24 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
       long lval;
       char ch = 'x';
 
-      if (++argn >= argc)      /* advance to next argument */
-       usage();
+      if (++argn >= argc)       /* advance to next argument */
+        usage();
       if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
-       usage();
+        usage();
       if (lval < 0 || lval > 65535L)
-       usage();
+        usage();
       if (ch == 'b' || ch == 'B') {
-       cinfo->restart_interval = (unsigned int) lval;
-       cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */
+        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 */
+        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();
+      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
@@ -383,13 +412,13 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
     } else if (keymatch(arg, "scans", 4)) {
       /* Set scan script. */
 #ifdef C_MULTISCAN_FILES_SUPPORTED
-      if (++argn >= argc)      /* advance to next argument */
-       usage();
+      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);
+      fprintf(stderr, "%s: sorry, multi-scan output was not compiled in\n",
+              progname);
       exit(EXIT_FAILURE);
 #endif
 
@@ -397,12 +426,12 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
       /* Set input smoothing factor. */
       int val;
 
-      if (++argn >= argc)      /* advance to next argument */
-       usage();
+      if (++argn >= argc)       /* advance to next argument */
+        usage();
       if (sscanf(argv[argn], "%d", &val) != 1)
-       usage();
+        usage();
       if (val < 0 || val > 100)
-       usage();
+        usage();
       cinfo->smoothing_factor = val;
 
     } else if (keymatch(arg, "targa", 1)) {
@@ -410,7 +439,7 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
       is_targa = TRUE;
 
     } else {
-      usage();                 /* bogus switch */
+      usage();                  /* bogus switch */
     }
   }
 
@@ -420,35 +449,35 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
 
     /* 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 (qualityarg != NULL)     /* process -quality if it was present */
       if (! set_quality_ratings(cinfo, qualityarg, force_baseline))
-       usage();
+        usage();
 
-    if (qtablefile != NULL)    /* process -qtables if it was present */
+    if (qtablefile != NULL)     /* process -qtables if it was present */
       if (! read_quant_tables(cinfo, qtablefile, force_baseline))
-       usage();
+        usage();
 
-    if (qslotsarg != NULL)     /* process -qslots if it was present */
+    if (qslotsarg != NULL)      /* process -qslots if it was present */
       if (! set_quant_slots(cinfo, qslotsarg))
-       usage();
+        usage();
 
-    if (samplearg != NULL)     /* process -sample if it was present */
+    if (samplearg != NULL)      /* process -sample if it was present */
       if (! set_sample_factors(cinfo, samplearg))
-       usage();
+        usage();
 
 #ifdef C_PROGRESSIVE_SUPPORTED
-    if (simple_progressive)    /* process -progressive; -scans can override */
+    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 (scansarg != NULL)       /* process -scans if it was present */
       if (! read_scan_script(cinfo, scansarg))
-       usage();
+        usage();
 #endif
   }
 
-  return argn;                 /* return index of next arg (file name) */
+  return argn;                  /* return index of next arg (file name) */
 }
 
 
@@ -466,8 +495,10 @@ main (int argc, char **argv)
 #endif
   int file_index;
   cjpeg_source_ptr src_mgr;
-  FILE * input_file;
-  FILE * output_file;
+  FILE *input_file;
+  FILE *output_file = NULL;
+  unsigned char *outbuffer = NULL;
+  unsigned long outsize = 0;
   JDIMENSION num_scanlines;
 
   /* On Mac, fetch a command line. */
@@ -477,7 +508,7 @@ main (int argc, char **argv)
 
   progname = argv[0];
   if (progname == NULL || progname[0] == 0)
-    progname = "cjpeg";                /* in case C library doesn't provide it */
+    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);
@@ -487,11 +518,6 @@ main (int argc, char **argv)
   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,
@@ -510,19 +536,21 @@ main (int argc, char **argv)
   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();
+  if (!memdst) {
+    /* 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
@@ -550,7 +578,7 @@ main (int argc, char **argv)
       fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
       exit(EXIT_FAILURE);
     }
-  } else {
+  } else if (!memdst) {
     /* default output file is stdout */
     output_file = write_stdout();
   }
@@ -573,7 +601,12 @@ main (int argc, char **argv)
   file_index = parse_switches(&cinfo, argc, argv, 0, TRUE);
 
   /* Specify data destination for compression */
-  jpeg_stdio_dest(&cinfo, output_file);
+#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
+  if (memdst)
+    jpeg_mem_dest(&cinfo, &outbuffer, &outsize);
+  else
+#endif
+    jpeg_stdio_dest(&cinfo, output_file);
 
   /* Start compressor */
   jpeg_start_compress(&cinfo, TRUE);
@@ -592,14 +625,20 @@ main (int argc, char **argv)
   /* Close files, if we opened them */
   if (input_file != stdin)
     fclose(input_file);
-  if (output_file != stdout)
+  if (output_file != stdout && output_file != NULL)
     fclose(output_file);
 
 #ifdef PROGRESS_REPORT
   end_progress_monitor((j_common_ptr) &cinfo);
 #endif
 
+  if (memdst) {
+    fprintf(stderr, "Compressed size:  %lu bytes\n", outsize);
+    if (outbuffer != NULL)
+      free(outbuffer);
+  }
+
   /* All done. */
   exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);
-  return 0;                    /* suppress no-return-value warnings */
+  return 0;                     /* suppress no-return-value warnings */
 }