Add support for scan optimisation of monochrome pictures
This commit is contained in:
@@ -3,6 +3,8 @@
|
|||||||
*
|
*
|
||||||
* Copyright (C) 1994-1996, Thomas G. Lane.
|
* Copyright (C) 1994-1996, Thomas G. Lane.
|
||||||
* This file is part of the Independent JPEG Group's software.
|
* 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 file.
|
* For conditions of distribution and use, see the accompanying README file.
|
||||||
*
|
*
|
||||||
* This file contains application interface code for the compression half
|
* This file contains application interface code for the compression half
|
||||||
@@ -43,6 +45,10 @@ jpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables)
|
|||||||
if (write_all_tables)
|
if (write_all_tables)
|
||||||
jpeg_suppress_tables(cinfo, FALSE); /* mark all tables to be written */
|
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 */
|
/* (Re)initialize error mgr and destination modules */
|
||||||
(*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
|
(*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
|
||||||
(*cinfo->dest->init_destination) (cinfo);
|
(*cinfo->dest->init_destination) (cinfo);
|
||||||
|
|||||||
145
jcmaster.c
145
jcmaster.c
@@ -644,92 +644,95 @@ select_scans (j_compress_ptr cinfo, int next_scan_number)
|
|||||||
for (i = 0; i < cinfo->num_scans_luma; i++)
|
for (i = 0; i < cinfo->num_scans_luma; i++)
|
||||||
free(cinfo->scan_buffer[i]);
|
free(cinfo->scan_buffer[i]);
|
||||||
|
|
||||||
} else if (next_scan_number == cinfo->num_scans_luma+cinfo->num_scans_chroma_dc) {
|
} else if (cinfo->num_scans > cinfo->num_scans_luma) {
|
||||||
base_scan_idx = cinfo->num_scans_luma;
|
|
||||||
|
|
||||||
if (cinfo->scan_size[base_scan_idx] <= cinfo->scan_size[base_scan_idx+1] + cinfo->scan_size[base_scan_idx+2])
|
if (next_scan_number == cinfo->num_scans_luma+cinfo->num_scans_chroma_dc) {
|
||||||
copy_buffer(cinfo, base_scan_idx);
|
base_scan_idx = cinfo->num_scans_luma;
|
||||||
else {
|
|
||||||
copy_buffer(cinfo, base_scan_idx+1);
|
|
||||||
copy_buffer(cinfo, base_scan_idx+2);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (next_scan_number == cinfo->num_scans_luma+cinfo->num_scans_chroma_dc+(6*cinfo->Al_max_chroma+4)) {
|
if (cinfo->scan_size[base_scan_idx] <= cinfo->scan_size[base_scan_idx+1] + cinfo->scan_size[base_scan_idx+2])
|
||||||
int Al;
|
copy_buffer(cinfo, base_scan_idx);
|
||||||
int i;
|
else {
|
||||||
base_scan_idx = cinfo->num_scans_luma + cinfo->num_scans_chroma_dc;
|
copy_buffer(cinfo, base_scan_idx+1);
|
||||||
cinfo->best_Al = 0;
|
copy_buffer(cinfo, base_scan_idx+2);
|
||||||
|
|
||||||
for (Al = 0; Al <= cinfo->Al_max_chroma; Al++) {
|
|
||||||
size[Al] = cinfo->scan_size[base_scan_idx + 0 + 4 * Al];
|
|
||||||
size[Al] += cinfo->scan_size[base_scan_idx + 1 + 4 * Al];
|
|
||||||
size[Al] += cinfo->scan_size[base_scan_idx + 2 + 4 * Al];
|
|
||||||
size[Al] += cinfo->scan_size[base_scan_idx + 3 + 4 * Al];
|
|
||||||
|
|
||||||
for (i = 0; i < Al; i++) {
|
|
||||||
size[Al] += cinfo->scan_size[base_scan_idx + 4 + 4*cinfo->Al_max_chroma + 2*i];
|
|
||||||
size[Al] += cinfo->scan_size[base_scan_idx + 5 + 4*cinfo->Al_max_chroma + 2*i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size[Al] < size[cinfo->best_Al])
|
} else if (next_scan_number == cinfo->num_scans_luma+cinfo->num_scans_chroma_dc+(6*cinfo->Al_max_chroma+4)) {
|
||||||
cinfo->best_Al = Al;
|
int Al;
|
||||||
}
|
int i;
|
||||||
|
base_scan_idx = cinfo->num_scans_luma + cinfo->num_scans_chroma_dc;
|
||||||
|
cinfo->best_Al = 0;
|
||||||
|
|
||||||
jpeg_scan_info *scanptr = (jpeg_scan_info *)&cinfo->scan_info[next_scan_number];
|
for (Al = 0; Al <= cinfo->Al_max_chroma; Al++) {
|
||||||
|
size[Al] = cinfo->scan_size[base_scan_idx + 0 + 4 * Al];
|
||||||
|
size[Al] += cinfo->scan_size[base_scan_idx + 1 + 4 * Al];
|
||||||
|
size[Al] += cinfo->scan_size[base_scan_idx + 2 + 4 * Al];
|
||||||
|
size[Al] += cinfo->scan_size[base_scan_idx + 3 + 4 * Al];
|
||||||
|
|
||||||
for (i = 0; i < 4*cinfo->num_frequency_splits+2; i++)
|
for (i = 0; i < Al; i++) {
|
||||||
scanptr[i].Al = cinfo->best_Al;
|
size[Al] += cinfo->scan_size[base_scan_idx + 4 + 4*cinfo->Al_max_chroma + 2*i];
|
||||||
|
size[Al] += cinfo->scan_size[base_scan_idx + 5 + 4*cinfo->Al_max_chroma + 2*i];
|
||||||
|
}
|
||||||
|
|
||||||
} else if (next_scan_number == cinfo->num_scans) {
|
if (size[Al] < size[cinfo->best_Al])
|
||||||
int Al;
|
cinfo->best_Al = Al;
|
||||||
int i;
|
}
|
||||||
base_scan_idx = next_scan_number - (4*cinfo->num_frequency_splits+2);
|
|
||||||
|
|
||||||
size[0] = cinfo->scan_size[base_scan_idx];
|
jpeg_scan_info *scanptr = (jpeg_scan_info *)&cinfo->scan_info[next_scan_number];
|
||||||
size[0] += cinfo->scan_size[base_scan_idx+1];
|
|
||||||
for (i = 0; i < cinfo->num_frequency_splits; i++) {
|
|
||||||
size[i+1] = cinfo->scan_size[base_scan_idx+0+4*i] + cinfo->scan_size[base_scan_idx+1+4*i];
|
|
||||||
size[i+1] += cinfo->scan_size[base_scan_idx+2+4*i] + cinfo->scan_size[base_scan_idx+3+4*i];
|
|
||||||
}
|
|
||||||
|
|
||||||
int best = 0;
|
for (i = 0; i < 4*cinfo->num_frequency_splits+2; i++)
|
||||||
if (size[1] < size[best])
|
scanptr[i].Al = cinfo->best_Al;
|
||||||
best = 1;
|
|
||||||
if (size[2] < size[best])
|
} else if (next_scan_number == cinfo->num_scans) {
|
||||||
best = 2;
|
int Al;
|
||||||
if (best != 0) {
|
int i;
|
||||||
if (size[3] < size[best])
|
base_scan_idx = next_scan_number - (4*cinfo->num_frequency_splits+2);
|
||||||
best = 3;
|
|
||||||
if (best == 2) {
|
size[0] = cinfo->scan_size[base_scan_idx];
|
||||||
if (size[4] < size[best]) {
|
size[0] += cinfo->scan_size[base_scan_idx+1];
|
||||||
best = 4;
|
for (i = 0; i < cinfo->num_frequency_splits; i++) {
|
||||||
if (size[5] < size[best])
|
size[i+1] = cinfo->scan_size[base_scan_idx+0+4*i] + cinfo->scan_size[base_scan_idx+1+4*i];
|
||||||
best = 5;
|
size[i+1] += cinfo->scan_size[base_scan_idx+2+4*i] + cinfo->scan_size[base_scan_idx+3+4*i];
|
||||||
|
}
|
||||||
|
|
||||||
|
int best = 0;
|
||||||
|
if (size[1] < size[best])
|
||||||
|
best = 1;
|
||||||
|
if (size[2] < size[best])
|
||||||
|
best = 2;
|
||||||
|
if (best != 0) {
|
||||||
|
if (size[3] < size[best])
|
||||||
|
best = 3;
|
||||||
|
if (best == 2) {
|
||||||
|
if (size[4] < size[best]) {
|
||||||
|
best = 4;
|
||||||
|
if (size[5] < size[best])
|
||||||
|
best = 5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (best == 0) {
|
if (best == 0) {
|
||||||
copy_buffer(cinfo, base_scan_idx);
|
copy_buffer(cinfo, base_scan_idx);
|
||||||
copy_buffer(cinfo, base_scan_idx+1);
|
copy_buffer(cinfo, base_scan_idx+1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
copy_buffer(cinfo, base_scan_idx-2+4*best);
|
copy_buffer(cinfo, base_scan_idx-2+4*best);
|
||||||
copy_buffer(cinfo, base_scan_idx-1+4*best);
|
copy_buffer(cinfo, base_scan_idx-1+4*best);
|
||||||
copy_buffer(cinfo, base_scan_idx+0+4*best);
|
copy_buffer(cinfo, base_scan_idx+0+4*best);
|
||||||
copy_buffer(cinfo, base_scan_idx-1+4*best);
|
copy_buffer(cinfo, base_scan_idx-1+4*best);
|
||||||
}
|
}
|
||||||
|
|
||||||
base_scan_idx = cinfo->num_scans_luma + cinfo->num_scans_chroma_dc;
|
base_scan_idx = cinfo->num_scans_luma + cinfo->num_scans_chroma_dc;
|
||||||
|
|
||||||
for (Al = cinfo->best_Al-1; Al >= 0; Al--) {
|
for (Al = cinfo->best_Al-1; Al >= 0; Al--) {
|
||||||
copy_buffer(cinfo, base_scan_idx + 4*(cinfo->Al_max_chroma+1) + 2*Al + 0);
|
copy_buffer(cinfo, base_scan_idx + 4*(cinfo->Al_max_chroma+1) + 2*Al + 0);
|
||||||
copy_buffer(cinfo, base_scan_idx + 4*(cinfo->Al_max_chroma+1) + 2*Al + 1);
|
copy_buffer(cinfo, base_scan_idx + 4*(cinfo->Al_max_chroma+1) + 2*Al + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free the memory allocated for the chroma buffers */
|
||||||
|
for (i = cinfo->num_scans_luma; i < cinfo->num_scans; i++)
|
||||||
|
free(cinfo->scan_buffer[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* free the memory allocated for the chroma buffers */
|
|
||||||
for (i = cinfo->num_scans_luma; i < cinfo->num_scans; i++)
|
|
||||||
free(cinfo->scan_buffer[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
101
jcparam.c
101
jcparam.c
@@ -612,12 +612,15 @@ fill_dc_scans (jpeg_scan_info * scanptr, int ncomps, int Ah, int Al)
|
|||||||
* cinfo->num_components and cinfo->jpeg_color_space must be correct.
|
* cinfo->num_components and cinfo->jpeg_color_space must be correct.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
LOCAL(void)
|
LOCAL(boolean)
|
||||||
jpeg_search_progression (j_compress_ptr cinfo)
|
jpeg_search_progression (j_compress_ptr cinfo)
|
||||||
{
|
{
|
||||||
int ncomps = cinfo->num_components;
|
int ncomps = cinfo->num_components;
|
||||||
int nscans;
|
int nscans;
|
||||||
jpeg_scan_info * scanptr;
|
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. */
|
/* Safety check to ensure start_compress not called yet. */
|
||||||
if (cinfo->global_state != CSTATE_START)
|
if (cinfo->global_state != CSTATE_START)
|
||||||
@@ -627,19 +630,11 @@ jpeg_search_progression (j_compress_ptr cinfo)
|
|||||||
if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) {
|
if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) {
|
||||||
/* Custom script for YCbCr color images. */
|
/* Custom script for YCbCr color images. */
|
||||||
nscans = 64;
|
nscans = 64;
|
||||||
|
} else if (ncomps == 1) {
|
||||||
|
nscans = 23;
|
||||||
} else {
|
} else {
|
||||||
/* All-purpose script for other color spaces. */
|
cinfo->num_scans_luma = 0;
|
||||||
if (cinfo->use_moz_defaults) {
|
return FALSE;
|
||||||
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.
|
/* Allocate space for script.
|
||||||
@@ -650,7 +645,7 @@ jpeg_search_progression (j_compress_ptr cinfo)
|
|||||||
* enough space to handle YCbCr even if initially asked for grayscale.
|
* enough space to handle YCbCr even if initially asked for grayscale.
|
||||||
*/
|
*/
|
||||||
if (cinfo->script_space == NULL || cinfo->script_space_size < nscans) {
|
if (cinfo->script_space == NULL || cinfo->script_space_size < nscans) {
|
||||||
cinfo->script_space_size = MAX(nscans, 10);
|
cinfo->script_space_size = MAX(nscans, 64);
|
||||||
cinfo->script_space = (jpeg_scan_info *)
|
cinfo->script_space = (jpeg_scan_info *)
|
||||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
||||||
cinfo->script_space_size * SIZEOF(jpeg_scan_info));
|
cinfo->script_space_size * SIZEOF(jpeg_scan_info));
|
||||||
@@ -659,44 +654,43 @@ jpeg_search_progression (j_compress_ptr cinfo)
|
|||||||
cinfo->scan_info = scanptr;
|
cinfo->scan_info = scanptr;
|
||||||
cinfo->num_scans = nscans;
|
cinfo->num_scans = nscans;
|
||||||
|
|
||||||
if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) {
|
cinfo->Al_max_luma = 3;
|
||||||
int Al;
|
cinfo->num_scans_luma_dc = 1;
|
||||||
int frequency_split[] = { 2, 8, 5, 12, 18 };
|
cinfo->num_frequency_splits = 5;
|
||||||
int i;
|
cinfo->num_scans_luma = cinfo->num_scans_luma_dc + (3 * cinfo->Al_max_luma + 2) + (2 * cinfo->num_frequency_splits + 1);
|
||||||
|
|
||||||
cinfo->Al_max_luma = 3;
|
/* 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);
|
||||||
|
|
||||||
|
for (Al = 0; Al <= cinfo->Al_max_luma; Al++) {
|
||||||
|
scanptr = fill_a_scan(scanptr, 0, 1, 8, 0, Al);
|
||||||
|
scanptr = fill_a_scan(scanptr, 0, 9, 63, 0, Al);
|
||||||
|
}
|
||||||
|
|
||||||
|
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, 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->Al_max_chroma = 2;
|
||||||
cinfo->num_scans_luma_dc = 1;
|
|
||||||
cinfo->num_scans_chroma_dc = 3;
|
cinfo->num_scans_chroma_dc = 3;
|
||||||
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);
|
|
||||||
|
|
||||||
for (Al = 0; Al <= cinfo->Al_max_luma; Al++) {
|
|
||||||
scanptr = fill_a_scan(scanptr, 0, 1, 8, 0, Al);
|
|
||||||
scanptr = fill_a_scan(scanptr, 0, 9, 63, 0, Al);
|
|
||||||
}
|
|
||||||
|
|
||||||
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, 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 41 scans for chroma */
|
/* 41 scans for chroma */
|
||||||
|
|
||||||
/* chroma DC combined */
|
/* chroma DC combined */
|
||||||
@@ -726,9 +720,9 @@ jpeg_search_progression (j_compress_ptr cinfo)
|
|||||||
scanptr = fill_a_scan(scanptr, 2, 1, frequency_split[i], 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);
|
scanptr = fill_a_scan(scanptr, 2, frequency_split[i]+1, 63, 0, 0);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
/* TODO */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -740,9 +734,10 @@ GLOBAL(void)
|
|||||||
jpeg_simple_progression (j_compress_ptr cinfo)
|
jpeg_simple_progression (j_compress_ptr cinfo)
|
||||||
{
|
{
|
||||||
if (cinfo->optimize_scans) {
|
if (cinfo->optimize_scans) {
|
||||||
jpeg_search_progression(cinfo);
|
if (jpeg_search_progression(cinfo) == TRUE)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ncomps = cinfo->num_components;
|
int ncomps = cinfo->num_components;
|
||||||
int nscans;
|
int nscans;
|
||||||
jpeg_scan_info * scanptr;
|
jpeg_scan_info * scanptr;
|
||||||
|
|||||||
Reference in New Issue
Block a user