Merge pull request #434 from felixbuenemann/jpeg-quant-table-option

Add mozjpeg quant_table option to jpegsave
This commit is contained in:
John Cupitt 2016-05-09 10:47:27 +01:00
commit 54e5cb04d3
4 changed files with 72 additions and 12 deletions

View File

@ -2217,6 +2217,7 @@ vips_jpegload_buffer( void *buf, size_t len, VipsImage **out, ... )
* * @trellis_quant: %gboolean, apply trellis quantisation to each 8x8 block
* * @overshoot_deringing: %gboolean, overshoot samples with extreme values
* * @optimize_scans: %gboolean, split DCT coefficients into separate scans
* * @quant_table: %gint, quantization table index
*
* Write a VIPS image to a file as JPEG.
*
@ -2268,6 +2269,30 @@ vips_jpegload_buffer( void *buf, size_t len, VipsImage **out, ... )
* (e.g. mozjpeg >= 3.0), split the spectrum of DCT coefficients into
* separate scans. Reduces file size but increases compression time.
*
* If @quant_table is set and the version of libjpeg supports it
* (e.g. mozjpeg >= 3.0) it selects the quantization table to use:
*
* * 0 Tables from JPEG Annex K (vips and libjpeg default)
* * 1 Flat table
* * 2 Table tuned for MSSIM on Kodak image set
* * 3 Table from ImageMagick by N. Robidoux (current mozjpeg default)
* * 4 Table tuned for PSNR-HVS-M on Kodak image set
* * 5 Table from Relevance of Human Vision to JPEG-DCT Compression (1992)
* * 6 Table from DCTune Perceptual Optimization of Compressed Dental X-Rays (1997)
* * 7 Table from A Visual Detection Model for DCT Coefficient Quantization (1993)
* * 8 Table from An Improved Detection Model for DCT Coefficient Quantization (1993)
*
* Quantization table 0 is the default in vips and libjpeg(-turbo), but it
* tends to favor detail over color accuracy, producting colored patches and
* stripes as well as heavy banding in flat areas at high compression ratios.
* Quantization table 2 is a good candidate to try if the default quantization
* table produces banding or color shifts and is well suited for hires images.
* Quantization table 3 is the default in mozjpeg and has been tuned to produce
* good results at the default quality setting; banding at high compression.
* Quantization table 4 is the most accurate at the cost of compression ratio.
* Tables 5-7 are based on older research papers, but generally achieve worse
* compression ratios and/or quality than 2 or 4.
*
* See also: vips_jpegsave_buffer(), vips_image_write_to_file().
*
* Returns: 0 on success, -1 on error.
@ -2303,6 +2328,7 @@ vips_jpegsave( VipsImage *in, const char *filename, ... )
* * @trellis_quant: %gboolean, apply trellis quantisation to each 8x8 block
* * @overshoot_deringing: %gboolean, overshoot samples with extreme values
* * @optimize_scans: %gboolean, split DCT coefficients into separate scans
* * @quant_table: %gint, quantization table index
*
* As vips_jpegsave(), but save to a memory buffer.
*
@ -2357,6 +2383,7 @@ vips_jpegsave_buffer( VipsImage *in, void **buf, size_t *len, ... )
* * @trellis_quant: %gboolean, apply trellis quantisation to each 8x8 block
* * @overshoot_deringing: %gboolean, overshoot samples with extreme values
* * @optimize_scans: %gboolean, split DCT coefficients into separate scans
* * @quant_table: %gint, quantization table index
*
* As vips_jpegsave(), but save as a mime jpeg on stdout.
*

View File

@ -103,6 +103,10 @@ typedef struct _VipsForeignSaveJpeg {
*/
gboolean optimize_scans;
/* Use predefined quantization table with given index.
*/
int quant_table;
} VipsForeignSaveJpeg;
typedef VipsForeignSaveClass VipsForeignSaveJpegClass;
@ -194,6 +198,13 @@ vips_foreign_save_jpeg_class_init( VipsForeignSaveJpegClass *class )
G_STRUCT_OFFSET( VipsForeignSaveJpeg, optimize_scans ),
FALSE );
VIPS_ARG_INT( class, "quant_table", 18,
_( "Quantization table" ),
_( "Use predefined quantization table with given index" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveJpeg, quant_table ),
0, 8, 0 );
}
static void
@ -230,7 +241,8 @@ vips_foreign_save_jpeg_file_build( VipsObject *object )
if( vips__jpeg_write_file( save->ready, file->filename,
jpeg->Q, jpeg->profile, jpeg->optimize_coding,
jpeg->interlace, save->strip, jpeg->no_subsample,
jpeg->trellis_quant, jpeg->overshoot_deringing, jpeg->optimize_scans) )
jpeg->trellis_quant, jpeg->overshoot_deringing,
jpeg->optimize_scans, jpeg->quant_table ) )
return( -1 );
return( 0 );
@ -294,7 +306,8 @@ vips_foreign_save_jpeg_buffer_build( VipsObject *object )
if( vips__jpeg_write_buffer( save->ready,
&obuf, &olen, jpeg->Q, jpeg->profile, jpeg->optimize_coding,
jpeg->interlace, save->strip, jpeg->no_subsample,
jpeg->trellis_quant, jpeg->overshoot_deringing, jpeg->optimize_scans) )
jpeg->trellis_quant, jpeg->overshoot_deringing,
jpeg->optimize_scans, jpeg->quant_table ) )
return( -1 );
blob = vips_blob_new( (VipsCallbackFn) vips_free, obuf, olen );
@ -357,7 +370,8 @@ vips_foreign_save_jpeg_mime_build( VipsObject *object )
if( vips__jpeg_write_buffer( save->ready,
&obuf, &olen, jpeg->Q, jpeg->profile, jpeg->optimize_coding,
jpeg->interlace, save->strip, jpeg->no_subsample,
jpeg->trellis_quant, jpeg->overshoot_deringing, jpeg->optimize_scans) )
jpeg->trellis_quant, jpeg->overshoot_deringing,
jpeg->optimize_scans, jpeg->quant_table ) )
return( -1 );
printf( "Content-length: %zu\r\n", olen );

View File

@ -966,7 +966,7 @@ static int
write_vips( Write *write, int qfac, const char *profile,
gboolean optimize_coding, gboolean progressive, gboolean strip,
gboolean no_subsample, gboolean trellis_quant,
gboolean overshoot_deringing, gboolean optimize_scans )
gboolean overshoot_deringing, gboolean optimize_scans, int quant_table )
{
VipsImage *in;
J_COLOR_SPACE space;
@ -1022,10 +1022,9 @@ write_vips( Write *write, int qfac, const char *profile,
JINT_COMPRESS_PROFILE, JCP_FASTEST );
#endif
/* Rest to default.
/* Reset to default.
*/
jpeg_set_defaults( &write->cinfo );
jpeg_set_quality( &write->cinfo, qfac, TRUE );
/* Compute optimal Huffman coding tables.
*/
@ -1077,6 +1076,20 @@ write_vips( Write *write, int qfac, const char *profile,
vips_warn( "vips2jpeg", "%s",
_( "Ignoring optimize_scans for baseline" ) );
}
/* Use predefined quantization table.
*/
if( quant_table > 0 ) {
if( jpeg_c_int_param_supported( &write->cinfo,
JINT_BASE_QUANT_TBL_IDX ) )
jpeg_c_set_int_param( &write->cinfo,
JINT_BASE_QUANT_TBL_IDX, quant_table );
else
vips_warn( "vips2jpeg",
"%s", _( "Setting quant_table unsupported" ) );
}
vips_warn( "vips2jpeg", "quant_table %d",
jpeg_c_get_int_param( &write->cinfo, JINT_BASE_QUANT_TBL_IDX ) );
#else
/* Using jpeglib.h without extension parameters, warn of ignored
* options.
@ -1088,8 +1101,14 @@ write_vips( Write *write, int qfac, const char *profile,
"%s", _( "Ignoring overshoot_deringing" ) );
if( optimize_scans )
vips_warn( "vips2jpeg", "%s", _( "Ignoring optimize_scans" ) );
if( quant_table > 0 )
vips_warn( "vips2jpeg", "%s", _( "Ignoring quant_table" ) );
#endif
/* Set compression quality. Must be called after setting params above.
*/
jpeg_set_quality( &write->cinfo, qfac, TRUE );
/* Enable progressive write.
*/
if( progressive )
@ -1160,7 +1179,7 @@ vips__jpeg_write_file( VipsImage *in,
const char *filename, int Q, const char *profile,
gboolean optimize_coding, gboolean progressive, gboolean strip,
gboolean no_subsample, gboolean trellis_quant,
gboolean overshoot_deringing, gboolean optimize_scans )
gboolean overshoot_deringing, gboolean optimize_scans, int quant_table )
{
Write *write;
@ -1192,7 +1211,7 @@ vips__jpeg_write_file( VipsImage *in,
*/
if( write_vips( write,
Q, profile, optimize_coding, progressive, strip, no_subsample,
trellis_quant, overshoot_deringing, optimize_scans ) ) {
trellis_quant, overshoot_deringing, optimize_scans, quant_table ) ) {
write_destroy( write );
return( -1 );
}
@ -1446,7 +1465,7 @@ vips__jpeg_write_buffer( VipsImage *in,
void **obuf, size_t *olen, int Q, const char *profile,
gboolean optimize_coding, gboolean progressive,
gboolean strip, gboolean no_subsample, gboolean trellis_quant,
gboolean overshoot_deringing, gboolean optimize_scans )
gboolean overshoot_deringing, gboolean optimize_scans, int quant_table )
{
Write *write;
@ -1477,7 +1496,7 @@ vips__jpeg_write_buffer( VipsImage *in,
*/
if( write_vips( write,
Q, profile, optimize_coding, progressive, strip, no_subsample,
trellis_quant, overshoot_deringing, optimize_scans ) ) {
trellis_quant, overshoot_deringing, optimize_scans, quant_table ) ) {
write_destroy( write );
return( -1 );

View File

@ -41,12 +41,12 @@ int vips__jpeg_write_file( VipsImage *in,
const char *filename, int Q, const char *profile,
gboolean optimize_coding, gboolean progressive, gboolean strip,
gboolean no_subsample, gboolean trellis_quant,
gboolean overshoot_deringing, gboolean optimize_scans );
gboolean overshoot_deringing, gboolean optimize_scans, int quant_table );
int vips__jpeg_write_buffer( VipsImage *in,
void **obuf, size_t *olen, int Q, const char *profile,
gboolean optimize_coding, gboolean progressive, gboolean strip,
gboolean no_subsample, gboolean trellis_quant,
gboolean overshoot_deringing, gboolean optimize_scans );
gboolean overshoot_deringing, gboolean optimize_scans, int quant_table );
int vips__isjpeg_buffer( const void *buf, size_t len );
int vips__isjpeg( const char *filename );