diff --git a/cjpeg.c b/cjpeg.c
index 07e7db1..76aba95 100644
--- a/cjpeg.c
+++ b/cjpeg.c
@@ -6,6 +6,8 @@
  * Modified 2003-2011 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
  * Copyright (C) 2010, 2013-2014, 2017, D. R. Commander.
+ * mozjpeg Modifications:
+ * Copyright (C) 2014, Mozilla Corporation.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -166,14 +168,16 @@ usage(void)
   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");
+  fprintf(stderr, "  -optimize      Optimize Huffman table (smaller file, but slow compression, enabled by default)\n");
 #endif
 #ifdef C_PROGRESSIVE_SUPPORTED
-  fprintf(stderr, "  -progressive   Create progressive JPEG file\n");
+  fprintf(stderr, "  -progressive   Create progressive JPEG file (enabled by default)\n");
 #endif
 #ifdef TARGA_SUPPORTED
   fprintf(stderr, "  -targa         Input file is Targa format (usually not needed)\n");
 #endif
+  fprintf(stderr, "  -revert        Revert to standard defaults (instead of mozjpeg defaults)\n");
+  fprintf(stderr, "  -fastcrush     Disable progressive scan optimization\n");
   fprintf(stderr, "Switches for advanced users:\n");
 #ifdef C_ARITH_CODING_SUPPORTED
   fprintf(stderr, "  -arithmetic    Use arithmetic coding\n");
@@ -239,7 +243,11 @@ parse_switches(j_compress_ptr cinfo, int argc, char **argv,
   /* Set up default JPEG parameters. */
 
   force_baseline = FALSE;       /* by default, allow 16-bit quantizers */
+#ifdef C_PROGRESSIVE_SUPPORTED
+  simple_progressive = cinfo->num_scans == 0 ? FALSE : TRUE;
+#else
   simple_progressive = FALSE;
+#endif
   is_targa = FALSE;
   icc_filename = NULL;
   outfilename = NULL;
@@ -302,6 +310,9 @@ parse_switches(j_compress_ptr cinfo, int argc, char **argv,
       }
       cinfo->err->trace_level++;
 
+    } else if (keymatch(arg, "fastcrush", 4)) {
+      cinfo->optimize_scans = FALSE;
+
     } else if (keymatch(arg, "version", 4)) {
       fprintf(stderr, "%s version %s (build %s)\n",
               PACKAGE_NAME, VERSION, BUILD);
@@ -414,6 +425,11 @@ parse_switches(j_compress_ptr cinfo, int argc, char **argv,
         /* restart_interval will be computed during startup */
       }
 
+    } else if (keymatch(arg, "revert", 3)) {
+      /* revert to old JPEG default */
+      cinfo->use_moz_defaults = FALSE;
+      jpeg_set_defaults(cinfo);
+
     } else if (keymatch(arg, "sample", 2)) {
       /* Set sampling factors. */
       if (++argn >= argc)       /* advance to next argument */
@@ -543,6 +559,7 @@ main(int argc, char **argv)
    */
 
   cinfo.in_color_space = JCS_RGB; /* arbitrary guess */
+  cinfo.use_moz_defaults = TRUE;
   jpeg_set_defaults(&cinfo);
 
   /* Scan command line to find file names.
diff --git a/jcapimin.c b/jcapimin.c
index 178c55b..7a75bba 100644
--- a/jcapimin.c
+++ b/jcapimin.c
@@ -92,6 +92,16 @@ jpeg_CreateCompress(j_compress_ptr cinfo, int version, size_t structsize)
 
   /* OK, I'm ready */
   cinfo->global_state = CSTATE_START;
+
+  /* The master struct is used to store extension parameters, so we allocate it
+   * here.  It is later reallocated by jinit_c_master_control().
+   */
+  cinfo->master = (struct jpeg_comp_master *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+                                  sizeof(struct jpeg_comp_master));
+  MEMZERO(cinfo->master, sizeof(struct jpeg_comp_master));
+
+  cinfo->master->compress_profile = JCP_MAX_COMPRESSION;
 }
 
 
diff --git a/jcapistd.c b/jcapistd.c
index aa2aad9..3e2490d 100644
--- a/jcapistd.c
+++ b/jcapistd.c
@@ -3,6 +3,8 @@
  *
  * Copyright (C) 1994-1996, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
+ * mozjpeg Modifications:
+ * Copyright (C) 2014, Mozilla Corporation.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -44,6 +46,10 @@ jpeg_start_compress(j_compress_ptr cinfo, boolean write_all_tables)
   if (write_all_tables)
     jpeg_suppress_tables(cinfo, FALSE); /* mark all tables to be written */
 
+  /* setting up scan optimisation pattern failed, disable scan optimisation */
+  if (cinfo->num_scans_luma == 0)
+    cinfo->optimize_scans = FALSE;
+  
   /* (Re)initialize error mgr and destination modules */
   (*cinfo->err->reset_error_mgr) ((j_common_ptr)cinfo);
   (*cinfo->dest->init_destination) (cinfo);
diff --git a/jcinit.c b/jcinit.c
index 78aa465..6bd1a0d 100644
--- a/jcinit.c
+++ b/jcinit.c
@@ -3,6 +3,8 @@
  *
  * Copyright (C) 1991-1997, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
+ * mozjpeg Modifications:
+ * Copyright (C) 2014, Mozilla Corporation.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -60,8 +62,8 @@ jinit_compress_master(j_compress_ptr cinfo)
   }
 
   /* Need a full-image coefficient buffer in any multi-pass mode. */
-  jinit_c_coef_controller(cinfo, (boolean)(cinfo->num_scans > 1 ||
-                                           cinfo->optimize_coding));
+  jinit_c_coef_controller(cinfo,
+      (boolean) (cinfo->num_scans > 1 || cinfo->optimize_coding || cinfo->optimize_scans));
   jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */);
 
   jinit_marker_writer(cinfo);
diff --git a/jcmarker.c b/jcmarker.c
index 801fbab..107a5a6 100644
--- a/jcmarker.c
+++ b/jcmarker.c
@@ -185,6 +185,74 @@ emit_dqt(j_compress_ptr cinfo, int index)
 }
 
 
+LOCAL(int)
+emit_multi_dqt (j_compress_ptr cinfo)
+/* Emits a DQT marker containing all quantization tables */
+/* Returns number of emitted 16-bit tables, or -1 for failed for baseline checking. */
+{
+  int prec[MAX_COMPONENTS];
+  int seen[MAX_COMPONENTS] = { 0 };
+  int fin_prec = 0;
+  int ci;
+  int size = 0;
+
+  if (cinfo->master->compress_profile == JCP_FASTEST)
+    return -1;
+
+  for (ci = 0; ci < cinfo->num_components; ci++) {
+    int tbl_num = cinfo->comp_info[ci].quant_tbl_no;
+    int i;
+    JQUANT_TBL * qtbl = cinfo->quant_tbl_ptrs[tbl_num];
+
+    if (qtbl == NULL || qtbl->sent_table == TRUE)
+      return -1;
+
+    prec[ci] = 0;
+    for (i = 0; i < DCTSIZE2; i++)
+      prec[ci] = !!(prec[ci] + (qtbl->quantval[i] > 255));
+
+    fin_prec += prec[ci];
+  }
+
+  emit_marker(cinfo, M_DQT);
+
+  for (ci = 0; ci < cinfo->num_components; ci++) {
+    int tbl_num = cinfo->comp_info[ci].quant_tbl_no;
+
+    if (!seen[tbl_num]) {
+      size += DCTSIZE2 * (prec[ci] + 1) + 1;
+      seen[tbl_num] = 1;
+    }
+  }
+  size += 2;
+
+  emit_2bytes(cinfo, size);
+
+  for (ci = 0; ci < cinfo->num_components; ci++) {
+    int tbl_num = cinfo->comp_info[ci].quant_tbl_no;
+    int i;
+    JQUANT_TBL * qtbl = cinfo->quant_tbl_ptrs[tbl_num];
+
+    if (qtbl->sent_table == TRUE)
+        continue;
+
+    emit_byte(cinfo, tbl_num + (prec[ci] << 4));
+
+    for (i = 0; i < DCTSIZE2; i++) {
+      unsigned int qval = qtbl->quantval[jpeg_natural_order[i]];
+
+      if (prec[ci])
+        emit_byte(cinfo, (int) (qval >> 8));
+      emit_byte(cinfo, (int) (qval & 0xFF));
+    }
+
+    qtbl->sent_table = TRUE;
+  }
+
+  return fin_prec;
+}
+
+
 LOCAL(void)
 emit_dht(j_compress_ptr cinfo, int index, boolean is_ac)
 /* Emit a DHT marker */
@@ -222,6 +290,113 @@ emit_dht(j_compress_ptr cinfo, int index, boolean is_ac)
   }
 }
 
+LOCAL(boolean)
+emit_multi_dht (j_compress_ptr cinfo)
+/* Emit all DHT markers */
+/* Returns FALSE on failure, TRUE otherwise. */
+{
+  int i, j;
+  int length = 2;
+  int dclens[NUM_HUFF_TBLS] = { 0 };
+  int aclens[NUM_HUFF_TBLS] = { 0 };
+  JHUFF_TBL *dcseen[NUM_HUFF_TBLS] = { NULL };
+  JHUFF_TBL *acseen[NUM_HUFF_TBLS] = { NULL };
+
+  /* Calclate the total length. */
+  for (i = 0; i < cinfo->comps_in_scan; i++) {
+    jpeg_component_info *compptr = cinfo->cur_comp_info[i];
+    int dcidx = compptr->dc_tbl_no;
+    int acidx = compptr->ac_tbl_no;
+    JHUFF_TBL *dctbl = cinfo->dc_huff_tbl_ptrs[dcidx];
+    JHUFF_TBL *actbl = cinfo->ac_huff_tbl_ptrs[acidx];
+    int seen = 0;
+
+    /* Handle DC table lenghts */
+    if (cinfo->Ss == 0 && cinfo->Ah == 0) {
+      if (dctbl == NULL)
+        ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dcidx);
+
+      if (dctbl->sent_table)
+          continue;
+
+      for (j = 0; j < NUM_HUFF_TBLS; j++)
+          seen += (dctbl == dcseen[j]);
+      if (seen)
+          continue;
+      dcseen[i] = dctbl;
+
+      for (j = 1; j <= 16; j++)
+        dclens[i] += dctbl->bits[j];
+      length += dclens[i] + 16 + 1;
+    }
+
+    /* Handle AC table lengths */
+    if (cinfo->Se) {
+      if (actbl == NULL)
+        ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, acidx + 0x10);
+
+      if (actbl->sent_table)
+          continue;
+
+      seen = 0;
+      for (j = 0; j < NUM_HUFF_TBLS; j++)
+          seen += (actbl == acseen[j]);
+      if (seen)
+          continue;
+      acseen[i] = actbl;
+
+      for (j = 1; j <= 16; j++)
+        aclens[i] += actbl->bits[j];
+      length += aclens[i] + 16 + 1;
+
+    }
+  }
+
+  /* Make sure we can fit it all into one DHT marker */
+  if (length > (1 << 16) - 1)
+    return FALSE;
+
+  emit_marker(cinfo, M_DHT);
+  emit_2bytes(cinfo, length);
+
+  for (i = 0; i < cinfo->comps_in_scan; i++) {
+    jpeg_component_info *compptr = cinfo->cur_comp_info[i];
+    int dcidx = compptr->dc_tbl_no;
+    int acidx = compptr->ac_tbl_no;
+    JHUFF_TBL *dctbl = cinfo->dc_huff_tbl_ptrs[dcidx];
+    JHUFF_TBL *actbl = cinfo->ac_huff_tbl_ptrs[acidx];
+
+    acidx += 0x10;
+
+    /* DC */
+    if (cinfo->Ss == 0 && cinfo->Ah == 0 && !dctbl->sent_table) {
+      emit_byte(cinfo, dcidx);
+
+      for (j = 1; j <= 16; j++)
+        emit_byte(cinfo, dctbl->bits[j]);
+
+      for (j = 0; j < dclens[i]; j++)
+        emit_byte(cinfo, dctbl->huffval[j]);
+
+      dctbl->sent_table = TRUE;
+    }
+
+    if (cinfo->Se && !actbl->sent_table) {
+      emit_byte(cinfo, acidx);
+
+      for (j = 1; j <= 16; j++)
+        emit_byte(cinfo, actbl->bits[j]);
+
+      for (j = 0; j < aclens[i]; j++)
+        emit_byte(cinfo, actbl->huffval[j]);
+
+      actbl->sent_table = TRUE;
+    }
+  }
+
+  return TRUE;
+}
+
 
 LOCAL(void)
 emit_dac(j_compress_ptr cinfo)
@@ -504,10 +679,13 @@ write_frame_header(j_compress_ptr cinfo)
   /* Emit DQT for each quantization table.
    * Note that emit_dqt() suppresses any duplicate tables.
    */
-  prec = 0;
-  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+  prec = emit_multi_dqt(cinfo);
+  if (prec == -1) {
+    prec = 0;
+    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
        ci++, compptr++) {
-    prec += emit_dqt(cinfo, compptr->quant_tbl_no);
+      prec += emit_dqt(cinfo, compptr->quant_tbl_no);
+    }
   }
   /* now prec is nonzero iff there are any 16-bit quant tables. */
 
@@ -571,14 +749,16 @@ write_scan_header(j_compress_ptr cinfo)
     /* Emit Huffman tables.
      * Note that emit_dht() suppresses any duplicate tables.
      */
-    for (i = 0; i < cinfo->comps_in_scan; i++) {
-      compptr = cinfo->cur_comp_info[i];
-      /* DC needs no table for refinement scan */
-      if (cinfo->Ss == 0 && cinfo->Ah == 0)
-        emit_dht(cinfo, compptr->dc_tbl_no, FALSE);
-      /* AC needs no table when not present */
-      if (cinfo->Se)
-        emit_dht(cinfo, compptr->ac_tbl_no, TRUE);
+    if (!emit_multi_dht(cinfo)) {
+      for (i = 0; i < cinfo->comps_in_scan; i++) {
+        compptr = cinfo->cur_comp_info[i];
+        /* DC needs no table for refinement scan */
+        if (cinfo->Ss == 0 && cinfo->Ah == 0)
+          emit_dht(cinfo, compptr->dc_tbl_no, FALSE);
+        /* AC needs no table when not present */
+        if (cinfo->Se)
+          emit_dht(cinfo, compptr->ac_tbl_no, TRUE);
+      }
     }
   }
 
diff --git a/jcmaster.c b/jcmaster.c
index 8516f4b..45f119a 100644
--- a/jcmaster.c
+++ b/jcmaster.c
@@ -6,6 +6,8 @@
  * Modified 2003-2010 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
  * Copyright (C) 2010, 2016, D. R. Commander.
+ * mozjpeg Modifications:
+ * Copyright (C) 2014, Mozilla Corporation.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -40,6 +42,16 @@ typedef struct {
 
   int scan_number;              /* current index in scan_info[] */
 
+  /* fields for scan optimisation */
+  unsigned char * scan_buffer[64]; /* buffer for a given scan */
+  unsigned long scan_size[64]; /* size for a given scan */
+  unsigned long best_cost; /* bit count for best frequency split */
+  int best_freq_split_idx_luma; /* index for best frequency split (luma) */
+  int best_freq_split_idx_chroma; /* index for best frequency split (chroma) */
+  int best_Al_luma; /* best value for Al found in scan search (luma) */
+  int best_Al_chroma; /* best value for Al found in scan search (luma) */
+  boolean interleave_chroma_dc; /* indicate whether to interleave chroma DC scans */
+  struct jpeg_destination_mgr * saved_dest; /* saved value of cinfo->dest */
   /*
    * This is here so we can add libjpeg-turbo version/build information to the
    * global string table without introducing a new global symbol.  Adding this
@@ -191,6 +203,14 @@ validate_script(j_compress_ptr cinfo)
   /* -1 until that coefficient has been seen; then last Al for it */
 #endif
 
+  if (cinfo->optimize_scans) {
+    cinfo->progressive_mode = TRUE;
+    /* When we optimize scans, there is redundancy in the scan list
+     * and this function will fail. Therefore skip all this checking
+     */
+    return;
+  }
+  
   if (cinfo->num_scans <= 0)
     ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, 0);
 
@@ -333,6 +353,16 @@ select_scan_parameters(j_compress_ptr cinfo)
     cinfo->Se = scanptr->Se;
     cinfo->Ah = scanptr->Ah;
     cinfo->Al = scanptr->Al;
+    if (cinfo->optimize_scans) {
+      /* luma frequency split passes */
+      if (master->scan_number >= cinfo->num_scans_luma_dc+3*cinfo->Al_max_luma+2 &&
+          master->scan_number < cinfo->num_scans_luma)
+        cinfo->Al = master->best_Al_luma;
+      /* chroma frequency split passes */
+      if (master->scan_number >= cinfo->num_scans_luma+cinfo->num_scans_chroma_dc+(6*cinfo->Al_max_chroma+4) &&
+          master->scan_number < cinfo->num_scans)
+        cinfo->Al = master->best_Al_chroma;
+    }
   } else
 #endif
   {
@@ -501,6 +531,13 @@ prepare_for_pass(j_compress_ptr cinfo)
       select_scan_parameters(cinfo);
       per_scan_setup(cinfo);
     }
+    if (cinfo->optimize_scans) {
+      master->saved_dest = cinfo->dest;
+      cinfo->dest = NULL;
+      master->scan_size[master->scan_number] = 0;
+      jpeg_mem_dest(cinfo, &master->scan_buffer[master->scan_number], &master->scan_size[master->scan_number]);
+      (*cinfo->dest->init_destination)(cinfo);
+    }
     (*cinfo->entropy->start_pass) (cinfo, FALSE);
     (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST);
     /* We emit frame/scan headers now */
@@ -543,6 +580,210 @@ pass_startup(j_compress_ptr cinfo)
 }
 
 
+LOCAL(void)
+copy_buffer (j_compress_ptr cinfo, int scan_idx)
+{
+  my_master_ptr master = (my_master_ptr) cinfo->master;
+  
+  unsigned long size = master->scan_size[scan_idx];
+  unsigned char * src = master->scan_buffer[scan_idx];
+  
+  while (size >= cinfo->dest->free_in_buffer)
+  {
+    MEMCOPY(cinfo->dest->next_output_byte, src, cinfo->dest->free_in_buffer);
+    src += cinfo->dest->free_in_buffer;
+    size -= cinfo->dest->free_in_buffer;
+    cinfo->dest->next_output_byte += cinfo->dest->free_in_buffer;
+    cinfo->dest->free_in_buffer = 0;
+    (*cinfo->dest->empty_output_buffer)(cinfo);
+  }
+
+  MEMCOPY(cinfo->dest->next_output_byte, src, size);
+  cinfo->dest->next_output_byte += size;
+  cinfo->dest->free_in_buffer -= size;
+}
+
+LOCAL(void)
+select_scans (j_compress_ptr cinfo, int next_scan_number)
+{
+  my_master_ptr master = (my_master_ptr) cinfo->master;
+  
+  unsigned long size[8];
+  int base_scan_idx;
+  int luma_freq_split_scan_start = cinfo->num_scans_luma_dc + 3 * cinfo->Al_max_luma + 2;
+  int chroma_freq_split_scan_start = cinfo->num_scans_luma+cinfo->num_scans_chroma_dc+(6*cinfo->Al_max_chroma+4);
+
+  if (next_scan_number > 1 && next_scan_number <= luma_freq_split_scan_start) {
+    if ((next_scan_number - 1) % 3 == 2) {
+      int Al = (next_scan_number - 1) / 3;
+      int i;
+      unsigned long cost = 0;
+      cost += master->scan_size[next_scan_number-2];
+      cost += master->scan_size[next_scan_number-1];
+      for (i = 0; i < Al; i++)
+        cost += master->scan_size[3 + 3*i];
+      
+      if (Al == 0 || cost < master->best_cost) {
+        master->best_cost = cost;
+        master->best_Al_luma = Al;
+      } else {
+        master->scan_number = luma_freq_split_scan_start - 1;
+        master->pass_number = 2 * master->scan_number + 1;
+      }
+    }
+  
+  } else if (next_scan_number > luma_freq_split_scan_start && next_scan_number <= cinfo->num_scans_luma) {
+    if (next_scan_number == luma_freq_split_scan_start + 1) {
+      master->best_freq_split_idx_luma = 0;
+      master->best_cost = master->scan_size[next_scan_number-1];
+      
+    } else if ((next_scan_number - luma_freq_split_scan_start) % 2 == 1) {
+      int idx = (next_scan_number - luma_freq_split_scan_start) >> 1;
+      unsigned long cost = 0;
+      cost += master->scan_size[next_scan_number-2];
+      cost += master->scan_size[next_scan_number-1];
+      
+      if (cost < master->best_cost) {
+        master->best_cost = cost;
+        master->best_freq_split_idx_luma = idx;
+      }
+      
+      /* if after testing first 3, no split is the best, don't search further */
+      if ((idx == 2 && master->best_freq_split_idx_luma == 0) ||
+          (idx == 3 && master->best_freq_split_idx_luma != 2) ||
+          (idx == 4 && master->best_freq_split_idx_luma != 4)) {
+        master->scan_number = cinfo->num_scans_luma - 1;
+        master->pass_number = 2 * master->scan_number + 1;
+        master->pub.is_last_pass = (master->pass_number == master->total_passes - 1);
+      }
+    }
+    
+  } else if (cinfo->num_scans > cinfo->num_scans_luma) {
+
+    if (next_scan_number == cinfo->num_scans_luma+cinfo->num_scans_chroma_dc) {
+      base_scan_idx = cinfo->num_scans_luma;
+      
+      master->interleave_chroma_dc = master->scan_size[base_scan_idx] <= master->scan_size[base_scan_idx+1] + master->scan_size[base_scan_idx+2];
+      
+    } else if (next_scan_number > cinfo->num_scans_luma+cinfo->num_scans_chroma_dc && next_scan_number <= chroma_freq_split_scan_start) {
+      base_scan_idx = cinfo->num_scans_luma + cinfo->num_scans_chroma_dc;
+      if ((next_scan_number - base_scan_idx) % 6 == 4) {
+        int Al = (next_scan_number - base_scan_idx) / 6;
+        int i;
+        unsigned long cost = 0;
+        cost += master->scan_size[next_scan_number-4];
+        cost += master->scan_size[next_scan_number-3];
+        cost += master->scan_size[next_scan_number-2];
+        cost += master->scan_size[next_scan_number-1];
+        for (i = 0; i < Al; i++) {
+          cost += master->scan_size[base_scan_idx + 4 + 6*i];
+          cost += master->scan_size[base_scan_idx + 5 + 6*i];
+        }
+        
+        if (Al == 0 || cost < master->best_cost) {
+          master->best_cost = cost;
+          master->best_Al_chroma = Al;
+        } else {
+          master->scan_number = chroma_freq_split_scan_start - 1;
+          master->pass_number = 2 * master->scan_number + 1;
+        }
+      }
+
+    } else if (next_scan_number > chroma_freq_split_scan_start && next_scan_number <= cinfo->num_scans) {
+      if (next_scan_number == chroma_freq_split_scan_start + 2) {
+        master->best_freq_split_idx_chroma = 0;
+        master->best_cost  = master->scan_size[next_scan_number-2];
+        master->best_cost += master->scan_size[next_scan_number-1];
+        
+      } else if ((next_scan_number - chroma_freq_split_scan_start) % 4 == 2) {
+        int idx = (next_scan_number - chroma_freq_split_scan_start) >> 2;
+        unsigned long cost = 0;
+        cost += master->scan_size[next_scan_number-4];
+        cost += master->scan_size[next_scan_number-3];
+        cost += master->scan_size[next_scan_number-2];
+        cost += master->scan_size[next_scan_number-1];
+        
+        if (cost < master->best_cost) {
+          master->best_cost = cost;
+          master->best_freq_split_idx_chroma = idx;
+        }
+        
+        /* if after testing first 3, no split is the best, don't search further */
+        if ((idx == 2 && master->best_freq_split_idx_chroma == 0) ||
+            (idx == 3 && master->best_freq_split_idx_chroma != 2) ||
+            (idx == 4 && master->best_freq_split_idx_chroma != 4)) {
+          master->scan_number = cinfo->num_scans - 1;
+          master->pass_number = 2 * master->scan_number + 1;
+          master->pub.is_last_pass = (master->pass_number == master->total_passes - 1);
+        }
+      }
+    }
+  }
+  
+  if (master->scan_number == cinfo->num_scans - 1) {
+    int i, Al;
+    int min_Al = MIN(master->best_Al_luma, master->best_Al_chroma);
+    
+    copy_buffer(cinfo, 0);
+
+    if (cinfo->num_scans > cinfo->num_scans_luma) {
+      base_scan_idx = cinfo->num_scans_luma;
+      
+      if (master->interleave_chroma_dc)
+        copy_buffer(cinfo, base_scan_idx);
+      else {
+        copy_buffer(cinfo, base_scan_idx+1);
+        copy_buffer(cinfo, base_scan_idx+2);
+      }
+    }
+    
+    if (master->best_freq_split_idx_luma == 0)
+      copy_buffer(cinfo, luma_freq_split_scan_start);
+    else {
+      copy_buffer(cinfo, luma_freq_split_scan_start+2*(master->best_freq_split_idx_luma-1)+1);
+      copy_buffer(cinfo, luma_freq_split_scan_start+2*(master->best_freq_split_idx_luma-1)+2);
+    }
+    
+    /* copy the LSB refinements as well */
+    for (Al = master->best_Al_luma-1; Al >= min_Al; Al--)
+      copy_buffer(cinfo, 3 + 3*Al);
+
+    if (cinfo->num_scans > cinfo->num_scans_luma) {
+      if (master->best_freq_split_idx_chroma == 0) {
+        copy_buffer(cinfo, chroma_freq_split_scan_start);
+        copy_buffer(cinfo, chroma_freq_split_scan_start+1);
+      }
+      else {
+        copy_buffer(cinfo, chroma_freq_split_scan_start+4*(master->best_freq_split_idx_chroma-1)+2);
+        copy_buffer(cinfo, chroma_freq_split_scan_start+4*(master->best_freq_split_idx_chroma-1)+3);
+        copy_buffer(cinfo, chroma_freq_split_scan_start+4*(master->best_freq_split_idx_chroma-1)+4);
+        copy_buffer(cinfo, chroma_freq_split_scan_start+4*(master->best_freq_split_idx_chroma-1)+5);
+      }
+      
+      base_scan_idx = cinfo->num_scans_luma + cinfo->num_scans_chroma_dc;
+      
+      for (Al = master->best_Al_chroma-1; Al >= min_Al; Al--) {
+        copy_buffer(cinfo, base_scan_idx + 6*Al + 4);
+        copy_buffer(cinfo, base_scan_idx + 6*Al + 5);
+      }
+    }
+    
+    for (Al = min_Al-1; Al >= 0; Al--) {
+      copy_buffer(cinfo, 3 + 3*Al);
+      
+      if (cinfo->num_scans > cinfo->num_scans_luma) {
+        copy_buffer(cinfo, base_scan_idx + 6*Al + 4);
+        copy_buffer(cinfo, base_scan_idx + 6*Al + 5);
+      }
+    }
+    
+    /* free the memory allocated for buffers */
+    for (i = 0; i < cinfo->num_scans; i++)
+      if (master->scan_buffer[i])
+        free(master->scan_buffer[i]);
+  }
+}
+
 /*
  * Finish up at end of pass.
  */
@@ -575,6 +816,12 @@ finish_pass_master(j_compress_ptr cinfo)
     /* next pass is either optimization or output of next scan */
     if (cinfo->optimize_coding)
       master->pass_type = huff_opt_pass;
+    if (cinfo->optimize_scans) {
+      (*cinfo->dest->term_destination)(cinfo);
+      cinfo->dest = master->saved_dest;
+      select_scans(cinfo, master->scan_number + 1);
+    }
+
     master->scan_number++;
     break;
   }
@@ -636,5 +883,13 @@ jinit_c_master_control(j_compress_ptr cinfo, boolean transcode_only)
   else
     master->total_passes = cinfo->num_scans;
 
+  if (cinfo->optimize_scans) {
+    int i;
+    master->best_Al_chroma = 0;
+    
+    for (i = 0; i < cinfo->num_scans; i++)
+      master->scan_buffer[i] = NULL;
+  }
+
   master->jpeg_version = PACKAGE_NAME " version " VERSION " (build " BUILD ")";
 }
diff --git a/jcparam.c b/jcparam.c
index bcea927..7a12caf 100644
--- a/jcparam.c
+++ b/jcparam.c
@@ -6,6 +6,8 @@
  * Modified 2003-2008 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
  * Copyright (C) 2009-2011, D. R. Commander.
+ * mozjpeg Modifications:
+ * Copyright (C) 2014, Mozilla Corporation.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -214,18 +216,39 @@ jpeg_set_defaults(j_compress_ptr cinfo)
     cinfo->arith_ac_K[i] = 5;
   }
 
+#ifdef C_PROGRESSIVE_SUPPORTED
+  cinfo->optimize_scans = TRUE;
+  if (cinfo->use_moz_defaults)
+    jpeg_simple_progression(cinfo);
+  else {
+    /* Default is no multiple-scan output */
+    cinfo->scan_info = NULL;
+    cinfo->num_scans = 0;
+  }
+#else
   /* Default is no multiple-scan output */
   cinfo->scan_info = NULL;
   cinfo->num_scans = 0;
-
+#endif
+  
   /* Expect normal source image, not raw downsampled data */
   cinfo->raw_data_in = FALSE;
 
   /* Use Huffman coding, not arithmetic coding, by default */
   cinfo->arith_code = FALSE;
 
+#ifdef ENTROPY_OPT_SUPPORTED
+  if (cinfo->use_moz_defaults)
+    /* By default, do extra passes to optimize entropy coding */
+    cinfo->optimize_coding = TRUE;
+  else
+    /* By default, don't do extra passes to optimize entropy coding */
+    cinfo->optimize_coding = FALSE;
+#else
   /* By default, don't do extra passes to optimize entropy coding */
   cinfo->optimize_coding = FALSE;
+#endif
+  
   /* The standard Huffman tables are only valid for 8-bit data precision.
    * If the precision is higher, force optimization on so that usable
    * tables will be computed.  This test can be removed if default tables
@@ -417,6 +440,22 @@ fill_a_scan(jpeg_scan_info *scanptr, int ci, int Ss, int Se, int Ah, int Al)
   return scanptr;
 }
 
+LOCAL(jpeg_scan_info *)
+fill_a_scan_pair (jpeg_scan_info * scanptr, int ci,
+             int Ss, int Se, int Ah, int Al)
+/* Support routine: generate one scan for pair of components */
+{
+  scanptr->comps_in_scan = 2;
+  scanptr->component_index[0] = ci;
+  scanptr->component_index[1] = ci + 1;
+  scanptr->Ss = Ss;
+  scanptr->Se = Se;
+  scanptr->Ah = Ah;
+  scanptr->Al = Al;
+  scanptr++;
+  return scanptr;
+}
+
 LOCAL(jpeg_scan_info *)
 fill_scans(jpeg_scan_info *scanptr, int ncomps, int Ss, int Se, int Ah, int Al)
 /* Support routine: generate one scan for each component */
@@ -458,6 +497,127 @@ fill_dc_scans(jpeg_scan_info *scanptr, int ncomps, int Ah, int Al)
 }
 
 
+/*
+ * List of scans to be tested
+ * cinfo->num_components and cinfo->jpeg_color_space must be correct.
+ */
+
+LOCAL(boolean)
+jpeg_search_progression (j_compress_ptr cinfo)
+{
+  int ncomps = cinfo->num_components;
+  int nscans;
+  jpeg_scan_info * scanptr;
+  int Al;
+  int frequency_split[] = { 2, 8, 5, 12, 18 };
+  int i;
+  
+  /* Safety check to ensure start_compress not called yet. */
+  if (cinfo->global_state != CSTATE_START)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+  
+  /* Figure space needed for script.  Calculation must match code below! */
+  if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) {
+    /* Custom script for YCbCr color images. */
+    nscans = 64;
+  } else if (ncomps == 1) {
+    nscans = 23;
+  } else {
+    cinfo->num_scans_luma = 0;
+    return FALSE;
+  }
+  
+  /* Allocate space for script.
+   * We need to put it in the permanent pool in case the application performs
+   * multiple compressions without changing the settings.  To avoid a memory
+   * leak if jpeg_simple_progression is called repeatedly for the same JPEG
+   * object, we try to re-use previously allocated space, and we allocate
+   * enough space to handle YCbCr even if initially asked for grayscale.
+   */
+  if (cinfo->script_space == NULL || cinfo->script_space_size < nscans) {
+    cinfo->script_space_size = MAX(nscans, 64);
+    cinfo->script_space = (jpeg_scan_info *)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+                                cinfo->script_space_size * sizeof(jpeg_scan_info));
+  }
+  scanptr = cinfo->script_space;
+  cinfo->scan_info = scanptr;
+  cinfo->num_scans = nscans;
+  
+  cinfo->Al_max_luma = 3;
+  cinfo->num_scans_luma_dc = 1;
+  cinfo->num_frequency_splits = 5;
+  cinfo->num_scans_luma = cinfo->num_scans_luma_dc + (3 * cinfo->Al_max_luma + 2) + (2 * cinfo->num_frequency_splits + 1);
+  
+  /* 23 scans for luma */
+  /* 1 scan for DC */
+  /* 11 scans to determine successive approximation */
+  /* 11 scans to determine frequency approximation */
+  /* after 12 scans need to update following 11 */
+  /* after 23 scans need to determine which to keep */
+  /* last 4 done conditionally */
+  
+  /* luma DC by itself */
+  scanptr = fill_dc_scans(scanptr, 1, 0, 0);
+  
+  scanptr = fill_a_scan(scanptr, 0, 1, 8, 0, 0);
+  scanptr = fill_a_scan(scanptr, 0, 9, 63, 0, 0);
+  
+  for (Al = 0; Al < cinfo->Al_max_luma; Al++) {
+    scanptr = fill_a_scan(scanptr, 0, 1, 63, Al+1, Al);
+    scanptr = fill_a_scan(scanptr, 0, 1, 8, 0, Al+1);
+    scanptr = fill_a_scan(scanptr, 0, 9, 63, 0, Al+1);
+  }
+  
+  scanptr = fill_a_scan(scanptr, 0, 1, 63, 0, 0);
+  
+  for (i = 0; i < cinfo->num_frequency_splits; i++) {
+    scanptr = fill_a_scan(scanptr, 0, 1, frequency_split[i], 0, 0);
+    scanptr = fill_a_scan(scanptr, 0, frequency_split[i]+1, 63, 0, 0);
+  }
+  
+  if (ncomps == 1) {
+    cinfo->Al_max_chroma = 0;
+    cinfo->num_scans_chroma_dc = 0;
+  } else {
+    cinfo->Al_max_chroma = 2;
+    cinfo->num_scans_chroma_dc = 3;
+    /* 41 scans for chroma */
+    
+    /* chroma DC combined */
+    scanptr = fill_a_scan_pair(scanptr, 1, 0, 0, 0, 0);
+    /* chroma DC separate */
+    scanptr = fill_a_scan(scanptr, 1, 0, 0, 0, 0);
+    scanptr = fill_a_scan(scanptr, 2, 0, 0, 0, 0);
+    
+    scanptr = fill_a_scan(scanptr, 1, 1, 8, 0, 0);
+    scanptr = fill_a_scan(scanptr, 1, 9, 63, 0, 0);
+    scanptr = fill_a_scan(scanptr, 2, 1, 8, 0, 0);
+    scanptr = fill_a_scan(scanptr, 2, 9, 63, 0, 0);
+
+    for (Al = 0; Al < cinfo->Al_max_chroma; Al++) {
+      scanptr = fill_a_scan(scanptr, 1, 1, 63, Al+1, Al);
+      scanptr = fill_a_scan(scanptr, 2, 1, 63, Al+1, Al);
+      scanptr = fill_a_scan(scanptr, 1, 1, 8, 0, Al+1);
+      scanptr = fill_a_scan(scanptr, 1, 9, 63, 0, Al+1);
+      scanptr = fill_a_scan(scanptr, 2, 1, 8, 0, Al+1);
+      scanptr = fill_a_scan(scanptr, 2, 9, 63, 0, Al+1);
+    }
+    
+    scanptr = fill_a_scan(scanptr, 1, 1, 63, 0, 0);
+    scanptr = fill_a_scan(scanptr, 2, 1, 63, 0, 0);
+
+    for (i = 0; i < cinfo->num_frequency_splits; i++) {
+      scanptr = fill_a_scan(scanptr, 1, 1, frequency_split[i], 0, 0);
+      scanptr = fill_a_scan(scanptr, 1, frequency_split[i]+1, 63, 0, 0);
+      scanptr = fill_a_scan(scanptr, 2, 1, frequency_split[i], 0, 0);
+      scanptr = fill_a_scan(scanptr, 2, frequency_split[i]+1, 63, 0, 0);
+    }
+  }
+  
+  return TRUE;
+}
+
 /*
  * Create a recommended progressive-JPEG script.
  * cinfo->num_components and cinfo->jpeg_color_space must be correct.
@@ -466,6 +626,11 @@ fill_dc_scans(jpeg_scan_info *scanptr, int ncomps, int Ah, int Al)
 GLOBAL(void)
 jpeg_simple_progression(j_compress_ptr cinfo)
 {
+  if (cinfo->optimize_scans) {
+    if (jpeg_search_progression(cinfo) == TRUE)
+      return;
+  }
+  
   int ncomps = cinfo->num_components;
   int nscans;
   jpeg_scan_info *scanptr;
@@ -474,16 +639,34 @@ jpeg_simple_progression(j_compress_ptr cinfo)
   if (cinfo->global_state != CSTATE_START)
     ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
 
-  /* Figure space needed for script.  Calculation must match code below! */
+  /* Figure space needed for script. Calculation must match code below! */
+  ncomps = cinfo->num_components;
   if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) {
     /* Custom script for YCbCr color images. */
-    nscans = 10;
+    if (cinfo->master->compress_profile == JCP_MAX_COMPRESSION) {
+      if (cinfo->master->dc_scan_opt_mode == 0) {
+        nscans = 9; /* 1 DC scan for all components */
+      } else if (cinfo->master->dc_scan_opt_mode == 1) {
+        nscans = 11; /* 1 DC scan for each component */
+      } else {
+        nscans = 10; /* 1 DC scan for luminance and 1 DC scan for chroma */
+      }
+    } else {
+      nscans = 10; /* 2 DC scans and 8 AC scans */
+    }
   } else {
     /* All-purpose script for other color spaces. */
-    if (ncomps > MAX_COMPS_IN_SCAN)
-      nscans = 6 * ncomps;      /* 2 DC + 4 AC scans per component */
-    else
-      nscans = 2 + 4 * ncomps;  /* 2 DC scans; 4 AC scans per component */
+    if (cinfo->master->compress_profile == JCP_MAX_COMPRESSION) {
+      if (ncomps > MAX_COMPS_IN_SCAN)
+        nscans = 5 * ncomps; /* 2 DC + 4 AC scans per component */
+      else
+        nscans = 1 + 4 * ncomps; /* 2 DC scans; 4 AC scans per component */
+    } else {
+      if (ncomps > MAX_COMPS_IN_SCAN)
+        nscans = 6 * ncomps; /* 2 DC + 4 AC scans per component */
+      else
+        nscans = 2 + 4 * ncomps; /* 2 DC scans; 4 AC scans per component */
+    }
   }
 
   /* Allocate space for script.
@@ -505,36 +688,80 @@ jpeg_simple_progression(j_compress_ptr cinfo)
 
   if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) {
     /* Custom script for YCbCr color images. */
-    /* Initial DC scan */
-    scanptr = fill_dc_scans(scanptr, ncomps, 0, 1);
-    /* Initial AC scan: get some luma data out in a hurry */
-    scanptr = fill_a_scan(scanptr, 0, 1, 5, 0, 2);
-    /* Chroma data is too small to be worth expending many scans on */
-    scanptr = fill_a_scan(scanptr, 2, 1, 63, 0, 1);
-    scanptr = fill_a_scan(scanptr, 1, 1, 63, 0, 1);
-    /* Complete spectral selection for luma AC */
-    scanptr = fill_a_scan(scanptr, 0, 6, 63, 0, 2);
-    /* Refine next bit of luma AC */
-    scanptr = fill_a_scan(scanptr, 0, 1, 63, 2, 1);
-    /* Finish DC successive approximation */
-    scanptr = fill_dc_scans(scanptr, ncomps, 1, 0);
-    /* Finish AC successive approximation */
-    scanptr = fill_a_scan(scanptr, 2, 1, 63, 1, 0);
-    scanptr = fill_a_scan(scanptr, 1, 1, 63, 1, 0);
-    /* Luma bottom bit comes last since it's usually largest scan */
-    scanptr = fill_a_scan(scanptr, 0, 1, 63, 1, 0);
+    if (cinfo->master->compress_profile == JCP_MAX_COMPRESSION) {
+      /* scan defined in jpeg_scan_rgb.txt in jpgcrush */
+      /* Initial DC scan */
+      if (cinfo->master->dc_scan_opt_mode == 0) {
+        /* 1 DC scan for all components */
+        scanptr = fill_dc_scans(scanptr, ncomps, 0, 0);
+      } else if (cinfo->master->dc_scan_opt_mode == 1) {
+        /* 1 DC scan for each component */
+        scanptr = fill_a_scan(scanptr, 0, 0, 0, 0, 0);
+        scanptr = fill_a_scan(scanptr, 1, 0, 0, 0, 0);
+        scanptr = fill_a_scan(scanptr, 2, 0, 0, 0, 0);
+      } else {
+        /* 1 DC scan for luminance and 1 DC scan for chroma */
+        scanptr = fill_dc_scans(scanptr, 1, 0, 0);
+        scanptr = fill_a_scan_pair(scanptr, 1, 0, 0, 0, 0);
+      }
+      /* Low frequency AC scans */
+      scanptr = fill_a_scan(scanptr, 0, 1, 8, 0, 2);
+      scanptr = fill_a_scan(scanptr, 1, 1, 8, 0, 0);
+      scanptr = fill_a_scan(scanptr, 2, 1, 8, 0, 0);
+      /* Complete spectral selection for luma AC */
+      scanptr = fill_a_scan(scanptr, 0, 9, 63, 0, 2);
+      /* Finish luma AC successive approximation */
+      scanptr = fill_a_scan(scanptr, 0, 1, 63, 2, 1);
+      scanptr = fill_a_scan(scanptr, 0, 1, 63, 1, 0);
+      /* Complete spectral selection for chroma AC */
+      scanptr = fill_a_scan(scanptr, 1, 9, 63, 0, 0);
+      scanptr = fill_a_scan(scanptr, 2, 9, 63, 0, 0);
+    } else {
+      /* Initial DC scan */
+      scanptr = fill_dc_scans(scanptr, ncomps, 0, 1);
+      /* Initial AC scan: get some luma data out in a hurry */
+      scanptr = fill_a_scan(scanptr, 0, 1, 5, 0, 2);
+      /* Chroma data is too small to be worth expending many scans on */
+      scanptr = fill_a_scan(scanptr, 2, 1, 63, 0, 1);
+      scanptr = fill_a_scan(scanptr, 1, 1, 63, 0, 1);
+      /* Complete spectral selection for luma AC */
+      scanptr = fill_a_scan(scanptr, 0, 6, 63, 0, 2);
+      /* Refine next bit of luma AC */
+      scanptr = fill_a_scan(scanptr, 0, 1, 63, 2, 1);
+      /* Finish DC successive approximation */
+      scanptr = fill_dc_scans(scanptr, ncomps, 1, 0);
+      /* Finish AC successive approximation */
+      scanptr = fill_a_scan(scanptr, 2, 1, 63, 1, 0);
+      scanptr = fill_a_scan(scanptr, 1, 1, 63, 1, 0);
+      /* Luma bottom bit comes last since it's usually largest scan */
+      scanptr = fill_a_scan(scanptr, 0, 1, 63, 1, 0);
+    }
   } else {
     /* All-purpose script for other color spaces. */
-    /* Successive approximation first pass */
-    scanptr = fill_dc_scans(scanptr, ncomps, 0, 1);
-    scanptr = fill_scans(scanptr, ncomps, 1, 5, 0, 2);
-    scanptr = fill_scans(scanptr, ncomps, 6, 63, 0, 2);
-    /* Successive approximation second pass */
-    scanptr = fill_scans(scanptr, ncomps, 1, 63, 2, 1);
-    /* Successive approximation final pass */
-    scanptr = fill_dc_scans(scanptr, ncomps, 1, 0);
-    scanptr = fill_scans(scanptr, ncomps, 1, 63, 1, 0);
+    if (cinfo->master->compress_profile == JCP_MAX_COMPRESSION) {
+      /* scan defined in jpeg_scan_bw.txt in jpgcrush */
+      /* DC component, no successive approximation */
+      scanptr = fill_dc_scans(scanptr, ncomps, 0, 0);
+      /* Successive approximation first pass */
+      scanptr = fill_scans(scanptr, ncomps, 1, 8, 0, 2);
+      scanptr = fill_scans(scanptr, ncomps, 9, 63, 0, 2);
+      /* Successive approximation second pass */
+      scanptr = fill_scans(scanptr, ncomps, 1, 63, 2, 1);
+      /* Successive approximation final pass */
+      scanptr = fill_scans(scanptr, ncomps, 1, 63, 1, 0);
+    } else {
+      /* Successive approximation first pass */
+      scanptr = fill_dc_scans(scanptr, ncomps, 0, 1);
+      scanptr = fill_scans(scanptr, ncomps, 1, 5, 0, 2);
+      scanptr = fill_scans(scanptr, ncomps, 6, 63, 0, 2);
+      /* Successive approximation second pass */
+      scanptr = fill_scans(scanptr, ncomps, 1, 63, 2, 1);
+      /* Successive approximation final pass */
+      scanptr = fill_dc_scans(scanptr, ncomps, 1, 0);
+      scanptr = fill_scans(scanptr, ncomps, 1, 63, 1, 0);
+    }
   }
 }
 
+
 #endif /* C_PROGRESSIVE_SUPPORTED */
diff --git a/jcstest.c b/jcstest.c
index 8b1fe38..c602430 100644
--- a/jcstest.c
+++ b/jcstest.c
@@ -1,5 +1,7 @@
 /*
  * Copyright (C)2011 D. R. Commander.  All Rights Reserved.
+ * mozjpeg Modifications:
+ * Copyright (C) 2014, Mozilla Corporation.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -85,6 +87,7 @@ int main(void)
 
   jpeg_create_compress(&cinfo);
   cinfo.input_components = 3;
+  cinfo.use_moz_defaults = TRUE;
   jpeg_set_defaults(&cinfo);
   cinfo.in_color_space = JCS_EXT_RGB;
   jpeg_default_colorspace(&cinfo);
diff --git a/jpegint.h b/jpegint.h
index ad36ca8..359a8c6 100644
--- a/jpegint.h
+++ b/jpegint.h
@@ -67,6 +67,26 @@ struct jpeg_comp_master {
   /* State variables made visible to other modules */
   boolean call_pass_startup;    /* True if pass_startup must be called */
   boolean is_last_pass;         /* True during last pass */
+
+  /* Extension parameters */
+  int compress_profile; /* compression profile */
+  boolean use_moz_defaults; /* TRUE=use Mozilla defaults */
+  boolean optimize_scans; /* TRUE=optimize progressive coding scans */
+  int dc_scan_opt_mode; /* DC scan optimization mode */
+  int num_scans_luma; /* # of entries in scan_info array pertaining to luma (used when optimize_scans is TRUE */
+  int num_scans_luma_dc;
+  int num_scans_chroma_dc;
+  int num_frequency_splits;
+
+  int Al_max_luma; /* maximum value of Al tested when optimizing scans (luma) */
+  int Al_max_chroma; /* maximum value of Al tested when optimizing scans (chroma) */
+};
+
+/* Values for the JINT_COMPRESS_PROFILE parameter (32-bit GUIDs) */
+
+enum {
+  JCP_MAX_COMPRESSION = 0x5D083AAD, /* best compression ratio (progressive, all mozjpeg extensions) */
+  JCP_FASTEST = 0x2AEA5CB4 /* libjpeg[-turbo] defaults (baseline, no mozjpeg extensions) */
 };
 
 /* Main buffer control (downsampled-data buffer) */
diff --git a/jpeglib.h b/jpeglib.h
index 33f8ad2..be0d240 100644
--- a/jpeglib.h
+++ b/jpeglib.h
@@ -7,6 +7,8 @@
  * libjpeg-turbo Modifications:
  * Copyright (C) 2009-2011, 2013-2014, 2016-2017, D. R. Commander.
  * Copyright (C) 2015, Google, Inc.
+ * mozjpeg Modifications:
+ * Copyright (C) 2014, Mozilla Corporation.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -374,6 +376,17 @@ struct jpeg_compress_struct {
   int smoothing_factor;         /* 1..100, or 0 for no input smoothing */
   J_DCT_METHOD dct_method;      /* DCT algorithm selector */
 
+  boolean use_moz_defaults; /* TRUE if using Mozilla defaults */
+  boolean optimize_scans; /* TRUE=optimize progressive coding scans */
+  
+  int num_scans_luma; /* # of entries in scan_info array pertaining to luma (used when optimize_scans is TRUE */
+  int num_scans_luma_dc;
+  int num_scans_chroma_dc;
+  int num_frequency_splits;
+  
+  int Al_max_luma; /* maximum value of Al tested when optimizing scans (luma) */
+  int Al_max_chroma; /* maximum value of Al tested when optimizing scans (chroma) */
+
   /* The restart interval can be specified in absolute MCUs by setting
    * restart_interval, or in MCU rows by setting restart_in_rows
    * (in which case the correct restart_interval will be figured
diff --git a/jpegtran.c b/jpegtran.c
index 058e844..8f0d7e4 100644
--- a/jpegtran.c
+++ b/jpegtran.c
@@ -5,6 +5,8 @@
  * Copyright (C) 1995-2010, Thomas G. Lane, Guido Vollbeding.
  * libjpeg-turbo Modifications:
  * Copyright (C) 2010, 2014, 2017, D. R. Commander.
+ * mozjpeg Modifications:
+ * Copyright (C) 2014, Mozilla Corporation.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -44,6 +46,8 @@ static char *icc_filename;      /* for -icc switch */
 static char *outfilename;       /* for -outfile switch */
 static JCOPY_OPTION copyoption; /* -copy switch */
 static jpeg_transform_info transformoption; /* image transformation options */
+boolean memsrc;  /* for -memsrc switch */
+#define INPUT_BUF_SIZE  4096
 
 
 LOCAL(void)
@@ -62,11 +66,13 @@ usage(void)
   fprintf(stderr, "  -copy comments Copy only comment markers (default)\n");
   fprintf(stderr, "  -copy all      Copy all extra markers\n");
 #ifdef ENTROPY_OPT_SUPPORTED
-  fprintf(stderr, "  -optimize      Optimize Huffman table (smaller file, but slow compression)\n");
+  fprintf(stderr, "  -optimize      Optimize Huffman table (smaller file, but slow compression, enabled by default)\n");
 #endif
 #ifdef C_PROGRESSIVE_SUPPORTED
-  fprintf(stderr, "  -progressive   Create progressive JPEG file\n");
+  fprintf(stderr, "  -progressive   Create progressive JPEG file (enabled by default)\n");
 #endif
+  fprintf(stderr, "  -revert        Revert to standard defaults (instead of mozjpeg defaults)\n");
+  fprintf(stderr, "  -fastcrush     Disable progressive scan optimization\n");
   fprintf(stderr, "Switches for modifying the image:\n");
 #if TRANSFORMS_SUPPORTED
   fprintf(stderr, "  -crop WxH+X+Y  Crop to a rectangular subarea\n");
@@ -139,7 +145,11 @@ parse_switches(j_compress_ptr cinfo, int argc, char **argv,
   char *scansarg = NULL;        /* saves -scans parm if any */
 
   /* Set up default JPEG parameters. */
+#ifdef C_PROGRESSIVE_SUPPORTED
+  simple_progressive = cinfo->num_scans == 0 ? FALSE : TRUE;
+#else
   simple_progressive = FALSE;
+#endif
   icc_filename = NULL;
   outfilename = NULL;
   copyoption = JCOPYOPT_DEFAULT;
@@ -233,6 +243,9 @@ parse_switches(j_compress_ptr cinfo, int argc, char **argv,
       else
         usage();
 
+    } else if (keymatch(arg, "fastcrush", 4)) {
+      cinfo->optimize_scans = FALSE;
+
     } else if (keymatch(arg, "grayscale", 1) ||
                keymatch(arg, "greyscale", 1)) {
       /* Force to grayscale. */
@@ -312,6 +325,10 @@ parse_switches(j_compress_ptr cinfo, int argc, char **argv,
         /* restart_interval will be computed during startup */
       }
 
+    } else if (keymatch(arg, "revert", 3)) {
+      /* revert to old JPEG default */
+      cinfo->use_moz_defaults = FALSE;
+      
     } else if (keymatch(arg, "rotate", 2)) {
       /* Rotate 90, 180, or 270 degrees (measured clockwise). */
       if (++argn >= argc)       /* advance to next argument */
@@ -399,6 +416,11 @@ main(int argc, char **argv)
   JOCTET *icc_profile = NULL;
   long icc_len = 0;
 
+  unsigned char *inbuffer = NULL;
+  unsigned long insize = 0;
+  unsigned char *outbuffer = NULL;
+  unsigned long outsize = 0;
+
   /* On Mac, fetch a command line. */
 #ifdef USE_CCOMMAND
   argc = ccommand(&argv);
@@ -414,6 +436,7 @@ main(int argc, char **argv)
   /* Initialize the JPEG compression object with default error handling. */
   dstinfo.err = jpeg_std_error(&jdsterr);
   jpeg_create_compress(&dstinfo);
+  dstinfo.use_moz_defaults = TRUE;
 
   /* Scan command line to find file names.
    * It is convenient to use just one switch-parsing routine, but the switch
@@ -497,7 +520,30 @@ main(int argc, char **argv)
 #endif
 
   /* Specify data source for decompression */
-  jpeg_stdio_src(&srcinfo, fp);
+  memsrc = TRUE; /* needed to revert to original */
+#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
+  if (memsrc) {
+    size_t nbytes;
+    do {
+      inbuffer = (unsigned char *)realloc(inbuffer, insize + INPUT_BUF_SIZE);
+      if (inbuffer == NULL) {
+        fprintf(stderr, "%s: memory allocation failure\n", progname);
+        exit(EXIT_FAILURE);
+      }
+      nbytes = JFREAD(fp, &inbuffer[insize], INPUT_BUF_SIZE);
+      if (nbytes < INPUT_BUF_SIZE && ferror(fp)) {
+        if (file_index < argc)
+          fprintf(stderr, "%s: can't read from %s\n", progname,
+                  argv[file_index]);
+        else
+          fprintf(stderr, "%s: can't read from stdin\n", progname);
+      }
+      insize += (unsigned long)nbytes;
+    } while (nbytes == INPUT_BUF_SIZE);
+    jpeg_mem_src(&srcinfo, inbuffer, insize);
+  } else
+#endif
+    jpeg_stdio_src(&srcinfo, fp);
 
   /* Enable saving of extra markers that we want to copy */
   jcopy_markers_setup(&srcinfo, copyoption);
@@ -560,7 +606,12 @@ main(int argc, char **argv)
   file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE);
 
   /* Specify data destination for compression */
-  jpeg_stdio_dest(&dstinfo, fp);
+#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
+  if (dstinfo.use_moz_defaults)
+    jpeg_mem_dest(&dstinfo, &outbuffer, &outsize);
+  else
+#endif
+    jpeg_stdio_dest(&dstinfo, fp);
 
   /* Start compressor (note no image data is actually written here) */
   jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
@@ -579,6 +630,27 @@ main(int argc, char **argv)
 
   /* Finish compression and release memory */
   jpeg_finish_compress(&dstinfo);
+  
+  if (dstinfo.use_moz_defaults) {
+    size_t nbytes;
+    
+    unsigned char *buffer = outbuffer;
+    unsigned long size = outsize;
+    if (insize < size) {
+      size = insize;
+      buffer = inbuffer;
+    }
+
+    nbytes = JFWRITE(fp, buffer, size);
+    if (nbytes < size && ferror(fp)) {
+      if (file_index < argc)
+        fprintf(stderr, "%s: can't write to %s\n", progname,
+                argv[file_index]);
+      else
+        fprintf(stderr, "%s: can't write to stdout\n", progname);
+    }
+  }
+    
   jpeg_destroy_compress(&dstinfo);
   (void)jpeg_finish_decompress(&srcinfo);
   jpeg_destroy_decompress(&srcinfo);
diff --git a/turbojpeg.c b/turbojpeg.c
index a41e8df..49191b8 100644
--- a/turbojpeg.c
+++ b/turbojpeg.c
@@ -1,5 +1,7 @@
 /*
  * Copyright (C)2009-2018 D. R. Commander.  All Rights Reserved.
+ * mozjpeg Modifications:
+ * Copyright (C) 2014, Mozilla Corporation.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -235,6 +237,7 @@ static int setCompDefaults(struct jpeg_compress_struct *cinfo, int pixelFormat,
 
   cinfo->in_color_space = pf2cs[pixelFormat];
   cinfo->input_components = tjPixelSize[pixelFormat];
+  cinfo->use_moz_defaults = TRUE;
   jpeg_set_defaults(cinfo);
 
 #ifndef NO_GETENV
