diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index c97c2d10..d6000680 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -2461,6 +2461,7 @@ vips_webpload_buffer( void *buf, size_t len, VipsImage **out, ... ) * @lossless: enables lossless compression * @preset: #VipsForeignWebpPreset choose lossy compression preset * @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(). * @@ -2492,6 +2493,7 @@ vips_webpsave( VipsImage *in, const char *filename, ... ) * @lossless: enables lossless compression * @preset: #VipsForeignWebpPreset choose lossy compression preset * @smart_subsample: enables high quality chroma subsampling + * @near_lossless: use preprocessing in lossless mode (controlled by Q) * * See also: vips_webpsave(). * diff --git a/libvips/foreign/vips2webp.c b/libvips/foreign/vips2webp.c index c0505f67..e8661cdd 100644 --- a/libvips/foreign/vips2webp.c +++ b/libvips/foreign/vips2webp.c @@ -85,7 +85,7 @@ get_preset( VipsForeignWebpPreset preset ) static int write_webp( WebPPicture *pic, VipsImage *in, int Q, gboolean lossless, VipsForeignWebpPreset preset, - gboolean smart_subsample ) + gboolean smart_subsample, gboolean near_lossless ) { VipsImage *memory; WebPConfig config; @@ -97,9 +97,11 @@ write_webp( WebPPicture *pic, VipsImage *in, return( -1 ); } - config.lossless = lossless; + config.lossless = lossless || near_lossless; if( smart_subsample ) config.preprocessing |= 4; + if( near_lossless ) + config.near_lossless = Q; if( !WebPValidateConfig(&config) ) { vips_error( "vips2webp", @@ -113,7 +115,7 @@ write_webp( WebPPicture *pic, VipsImage *in, /* Smart subsampling requires use_argb because * 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->height = memory->Ysize; @@ -145,7 +147,7 @@ write_webp( WebPPicture *pic, VipsImage *in, int vips__webp_write_file( VipsImage *in, const char *filename, int Q, gboolean lossless, VipsForeignWebpPreset preset, - gboolean smart_subsample ) + gboolean smart_subsample, gboolean near_lossless ) { WebPPicture pic; WebPMemoryWriter writer; @@ -161,7 +163,8 @@ vips__webp_write_file( VipsImage *in, const char *filename, pic.writer = WebPMemoryWrite; 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 ); WebPMemoryWriterClear( &writer ); return -1; @@ -189,7 +192,7 @@ vips__webp_write_file( VipsImage *in, const char *filename, int vips__webp_write_buffer( VipsImage *in, void **obuf, size_t *olen, int Q, gboolean lossless, VipsForeignWebpPreset preset, - gboolean smart_subsample ) + gboolean smart_subsample, gboolean near_lossless ) { WebPPicture pic; WebPMemoryWriter writer; @@ -205,7 +208,8 @@ vips__webp_write_buffer( VipsImage *in, void **obuf, size_t *olen, pic.writer = WebPMemoryWrite; 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 ); WebPMemoryWriterClear( &writer ); return -1; diff --git a/libvips/foreign/webp.h b/libvips/foreign/webp.h index 0d934198..500b22b5 100644 --- a/libvips/foreign/webp.h +++ b/libvips/foreign/webp.h @@ -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 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 Q, gboolean lossless, VipsForeignWebpPreset preset, - gboolean smart_subsample ); + gboolean smart_subsample, gboolean near_lossless ); #ifdef __cplusplus } diff --git a/libvips/foreign/webpsave.c b/libvips/foreign/webpsave.c index 29e647c7..5989c300 100644 --- a/libvips/foreign/webpsave.c +++ b/libvips/foreign/webpsave.c @@ -68,6 +68,10 @@ typedef struct _VipsForeignSaveWebp { */ gboolean smart_subsample; + /* Use preprocessing in lossless mode. + */ + gboolean near_lossless; + } VipsForeignSaveWebp; typedef VipsForeignSaveClass VipsForeignSaveWebpClass; @@ -108,7 +112,7 @@ vips_foreign_save_webp_class_init( VipsForeignSaveWebpClass *class ) _( "Q factor" ), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET( VipsForeignSaveWebp, Q ), - 1, 100, 75 ); + 0, 100, 75 ); VIPS_ARG_BOOL( class, "lossless", 11, _( "lossless" ), @@ -132,6 +136,13 @@ vips_foreign_save_webp_class_init( VipsForeignSaveWebpClass *class ) G_STRUCT_OFFSET( VipsForeignSaveWebp, smart_subsample ), 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 @@ -167,7 +178,7 @@ vips_foreign_save_webp_file_build( VipsObject *object ) if( vips__webp_write_file( save->ready, file->filename, webp->Q, webp->lossless, webp->preset, - webp->smart_subsample ) ) + webp->smart_subsample, webp->near_lossless ) ) return( -1 ); return( 0 ); @@ -230,7 +241,7 @@ vips_foreign_save_webp_buffer_build( VipsObject *object ) if( vips__webp_write_buffer( save->ready, &obuf, &olen, webp->Q, webp->lossless, webp->preset, - webp->smart_subsample ) ) + webp->smart_subsample, webp->near_lossless ) ) return( -1 ); 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, webp->Q, webp->lossless, webp->preset, - webp->smart_subsample ) ) + webp->smart_subsample, webp->near_lossless ) ) return( -1 ); printf( "Content-length: %zu\r\n", olen );