Add webpsave near_lossless support, fix Q range

The near_lossless option allows to enable preprocessing for the lossless
mode. This is a boolean instead of an int, because the amount of
preprocessing is controlled using the Q factor parameter which is
otherwise unused in lossless mode. This allows to re-use the quality
setting in existing tools.
This commit is contained in:
Felix Bünemann 2016-04-23 02:00:32 +02:00
parent 58a2616f77
commit c107066c4e
4 changed files with 30 additions and 13 deletions

View File

@ -2461,6 +2461,7 @@ vips_webpload_buffer( void *buf, size_t len, VipsImage **out, ... )
* @lossless: enables lossless compression * @lossless: enables lossless compression
* @preset: #VipsForeignWebpPreset choose lossy compression preset * @preset: #VipsForeignWebpPreset choose lossy compression preset
* @smart_subsample: enables high quality chroma subsampling * @smart_subsample: enables high quality chroma subsampling
* @near_lossless: use preprocessing in lossless mode (controlled by Q)
* *
* See also: vips_webpload(), vips_image_write_to_file(). * See also: vips_webpload(), vips_image_write_to_file().
* *
@ -2492,6 +2493,7 @@ vips_webpsave( VipsImage *in, const char *filename, ... )
* @lossless: enables lossless compression * @lossless: enables lossless compression
* @preset: #VipsForeignWebpPreset choose lossy compression preset * @preset: #VipsForeignWebpPreset choose lossy compression preset
* @smart_subsample: enables high quality chroma subsampling * @smart_subsample: enables high quality chroma subsampling
* @near_lossless: use preprocessing in lossless mode (controlled by Q)
* *
* See also: vips_webpsave(). * See also: vips_webpsave().
* *

View File

@ -85,7 +85,7 @@ get_preset( VipsForeignWebpPreset preset )
static int static int
write_webp( WebPPicture *pic, VipsImage *in, write_webp( WebPPicture *pic, VipsImage *in,
int Q, gboolean lossless, VipsForeignWebpPreset preset, int Q, gboolean lossless, VipsForeignWebpPreset preset,
gboolean smart_subsample ) gboolean smart_subsample, gboolean near_lossless )
{ {
VipsImage *memory; VipsImage *memory;
WebPConfig config; WebPConfig config;
@ -97,9 +97,11 @@ write_webp( WebPPicture *pic, VipsImage *in,
return( -1 ); return( -1 );
} }
config.lossless = lossless; config.lossless = lossless || near_lossless;
if( smart_subsample ) if( smart_subsample )
config.preprocessing |= 4; config.preprocessing |= 4;
if( near_lossless )
config.near_lossless = Q;
if( !WebPValidateConfig(&config) ) { if( !WebPValidateConfig(&config) ) {
vips_error( "vips2webp", vips_error( "vips2webp",
@ -113,7 +115,7 @@ write_webp( WebPPicture *pic, VipsImage *in,
/* Smart subsampling requires use_argb because /* Smart subsampling requires use_argb because
* it is applied during RGB to YUV conversion. * it is applied during RGB to YUV conversion.
*/ */
pic->use_argb = lossless || smart_subsample; pic->use_argb = lossless || near_lossless || smart_subsample;
pic->width = memory->Xsize; pic->width = memory->Xsize;
pic->height = memory->Ysize; pic->height = memory->Ysize;
@ -145,7 +147,7 @@ write_webp( WebPPicture *pic, VipsImage *in,
int int
vips__webp_write_file( VipsImage *in, const char *filename, vips__webp_write_file( VipsImage *in, const char *filename,
int Q, gboolean lossless, VipsForeignWebpPreset preset, int Q, gboolean lossless, VipsForeignWebpPreset preset,
gboolean smart_subsample ) gboolean smart_subsample, gboolean near_lossless )
{ {
WebPPicture pic; WebPPicture pic;
WebPMemoryWriter writer; WebPMemoryWriter writer;
@ -161,7 +163,8 @@ vips__webp_write_file( VipsImage *in, const char *filename,
pic.writer = WebPMemoryWrite; pic.writer = WebPMemoryWrite;
pic.custom_ptr = &writer; pic.custom_ptr = &writer;
if( write_webp( &pic, in, Q, lossless, preset, smart_subsample ) ) { if( write_webp( &pic, in, Q, lossless, preset, smart_subsample,
near_lossless ) ) {
WebPPictureFree( &pic ); WebPPictureFree( &pic );
WebPMemoryWriterClear( &writer ); WebPMemoryWriterClear( &writer );
return -1; return -1;
@ -189,7 +192,7 @@ vips__webp_write_file( VipsImage *in, const char *filename,
int int
vips__webp_write_buffer( VipsImage *in, void **obuf, size_t *olen, vips__webp_write_buffer( VipsImage *in, void **obuf, size_t *olen,
int Q, gboolean lossless, VipsForeignWebpPreset preset, int Q, gboolean lossless, VipsForeignWebpPreset preset,
gboolean smart_subsample ) gboolean smart_subsample, gboolean near_lossless )
{ {
WebPPicture pic; WebPPicture pic;
WebPMemoryWriter writer; WebPMemoryWriter writer;
@ -205,7 +208,8 @@ vips__webp_write_buffer( VipsImage *in, void **obuf, size_t *olen,
pic.writer = WebPMemoryWrite; pic.writer = WebPMemoryWrite;
pic.custom_ptr = &writer; pic.custom_ptr = &writer;
if( write_webp( &pic, in, Q, lossless, preset, smart_subsample ) ) { if( write_webp( &pic, in, Q, lossless, preset, smart_subsample,
near_lossless) ) {
WebPPictureFree( &pic ); WebPPictureFree( &pic );
WebPMemoryWriterClear( &writer ); WebPMemoryWriterClear( &writer );
return -1; return -1;

View File

@ -50,10 +50,10 @@ int vips__webp_read_buffer( const void *buf, size_t len,
int vips__webp_write_file( VipsImage *out, const char *filename, int vips__webp_write_file( VipsImage *out, const char *filename,
int Q, gboolean lossless, VipsForeignWebpPreset preset, int Q, gboolean lossless, VipsForeignWebpPreset preset,
gboolean smart_subsample ); gboolean smart_subsample, gboolean near_lossless );
int vips__webp_write_buffer( VipsImage *out, void **buf, size_t *len, int vips__webp_write_buffer( VipsImage *out, void **buf, size_t *len,
int Q, gboolean lossless, VipsForeignWebpPreset preset, int Q, gboolean lossless, VipsForeignWebpPreset preset,
gboolean smart_subsample ); gboolean smart_subsample, gboolean near_lossless );
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -68,6 +68,10 @@ typedef struct _VipsForeignSaveWebp {
*/ */
gboolean smart_subsample; gboolean smart_subsample;
/* Use preprocessing in lossless mode.
*/
gboolean near_lossless;
} VipsForeignSaveWebp; } VipsForeignSaveWebp;
typedef VipsForeignSaveClass VipsForeignSaveWebpClass; typedef VipsForeignSaveClass VipsForeignSaveWebpClass;
@ -108,7 +112,7 @@ vips_foreign_save_webp_class_init( VipsForeignSaveWebpClass *class )
_( "Q factor" ), _( "Q factor" ),
VIPS_ARGUMENT_OPTIONAL_INPUT, VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveWebp, Q ), G_STRUCT_OFFSET( VipsForeignSaveWebp, Q ),
1, 100, 75 ); 0, 100, 75 );
VIPS_ARG_BOOL( class, "lossless", 11, VIPS_ARG_BOOL( class, "lossless", 11,
_( "lossless" ), _( "lossless" ),
@ -132,6 +136,13 @@ vips_foreign_save_webp_class_init( VipsForeignSaveWebpClass *class )
G_STRUCT_OFFSET( VipsForeignSaveWebp, smart_subsample ), G_STRUCT_OFFSET( VipsForeignSaveWebp, smart_subsample ),
FALSE ); FALSE );
VIPS_ARG_BOOL( class, "near_lossless", 14,
_( "Near lossless" ),
_( "Enable preprocessing in lossless mode (uses Q)" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveWebp, near_lossless ),
FALSE );
} }
static void static void
@ -167,7 +178,7 @@ vips_foreign_save_webp_file_build( VipsObject *object )
if( vips__webp_write_file( save->ready, file->filename, if( vips__webp_write_file( save->ready, file->filename,
webp->Q, webp->lossless, webp->preset, webp->Q, webp->lossless, webp->preset,
webp->smart_subsample ) ) webp->smart_subsample, webp->near_lossless ) )
return( -1 ); return( -1 );
return( 0 ); return( 0 );
@ -230,7 +241,7 @@ vips_foreign_save_webp_buffer_build( VipsObject *object )
if( vips__webp_write_buffer( save->ready, &obuf, &olen, if( vips__webp_write_buffer( save->ready, &obuf, &olen,
webp->Q, webp->lossless, webp->preset, webp->Q, webp->lossless, webp->preset,
webp->smart_subsample ) ) webp->smart_subsample, webp->near_lossless ) )
return( -1 ); return( -1 );
blob = vips_blob_new( (VipsCallbackFn) vips_free, obuf, olen ); blob = vips_blob_new( (VipsCallbackFn) vips_free, obuf, olen );
@ -292,7 +303,7 @@ vips_foreign_save_webp_mime_build( VipsObject *object )
if( vips__webp_write_buffer( save->ready, &obuf, &olen, if( vips__webp_write_buffer( save->ready, &obuf, &olen,
webp->Q, webp->lossless, webp->preset, webp->Q, webp->lossless, webp->preset,
webp->smart_subsample ) ) webp->smart_subsample, webp->near_lossless ) )
return( -1 ); return( -1 );
printf( "Content-length: %zu\r\n", olen ); printf( "Content-length: %zu\r\n", olen );