diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index dd60b94b..a304ce08 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -2458,6 +2458,8 @@ vips_webpload_buffer( void *buf, size_t len, VipsImage **out, ... ) * Optional arguments: * * @Q: quality factor + * @lossless: enables lossless compression + * @preset: #VipsForeignWebpPreset choose lossy compression preset * * See also: vips_webpload(), vips_image_write_to_file(). * @@ -2486,6 +2488,8 @@ vips_webpsave( VipsImage *in, const char *filename, ... ) * Optional arguments: * * @Q: JPEG quality factor + * @lossless: enables lossless compression + * @preset: #VipsForeignWebpPreset choose lossy compression preset * * See also: vips_webpsave(). * diff --git a/libvips/foreign/vips2webp.c b/libvips/foreign/vips2webp.c index b5b91a16..6c7cab42 100644 --- a/libvips/foreign/vips2webp.c +++ b/libvips/foreign/vips2webp.c @@ -56,15 +56,41 @@ typedef int (*webp_import)( WebPPicture *picture, const uint8_t *rgb, int stride ); +static WebPPreset +get_preset( VipsForeignWebpPreset preset ) +{ + switch( preset ) { + case VIPS_FOREIGN_WEBP_PRESET_DEFAULT: + return( WEBP_PRESET_DEFAULT ); + case VIPS_FOREIGN_WEBP_PRESET_PICTURE: + return( WEBP_PRESET_PICTURE ); + case VIPS_FOREIGN_WEBP_PRESET_PHOTO: + return( WEBP_PRESET_PHOTO ); + case VIPS_FOREIGN_WEBP_PRESET_DRAWING: + return( WEBP_PRESET_DRAWING ); + case VIPS_FOREIGN_WEBP_PRESET_ICON: + return( WEBP_PRESET_ICON ); + case VIPS_FOREIGN_WEBP_PRESET_TEXT: + return( WEBP_PRESET_TEXT ); + + default: + g_assert_not_reached(); + } + + /* Keep -Wall happy. + */ + return( -1 ); +} + static int write_webp( WebPPicture *pic, VipsImage *in, - int Q, gboolean lossless ) + int Q, gboolean lossless, VipsForeignWebpPreset preset ) { VipsImage *memory; WebPConfig config; webp_import import; - if ( !WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, Q) ) { + if ( !WebPConfigPreset(&config, get_preset( preset ), Q) ) { vips_error( "vips2webp", "%s", _( "config version error" ) ); return( -1 ); @@ -112,7 +138,7 @@ write_webp( WebPPicture *pic, VipsImage *in, int vips__webp_write_file( VipsImage *in, const char *filename, - int Q, gboolean lossless ) + int Q, gboolean lossless, VipsForeignWebpPreset preset ) { WebPPicture pic; WebPMemoryWriter writer; @@ -128,7 +154,7 @@ vips__webp_write_file( VipsImage *in, const char *filename, pic.writer = WebPMemoryWrite; pic.custom_ptr = &writer; - if( write_webp( &pic, in, Q, lossless ) ) { + if( write_webp( &pic, in, Q, lossless, preset ) ) { WebPPictureFree( &pic ); WebPMemoryWriterClear( &writer ); return -1; @@ -155,7 +181,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 ) + int Q, gboolean lossless, VipsForeignWebpPreset preset ) { WebPPicture pic; WebPMemoryWriter writer; @@ -171,7 +197,7 @@ 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 ) ) { + if( write_webp( &pic, in, Q, lossless, preset ) ) { WebPPictureFree( &pic ); WebPMemoryWriterClear( &writer ); return -1; diff --git a/libvips/foreign/webp.h b/libvips/foreign/webp.h index 83e8653b..e1698239 100644 --- a/libvips/foreign/webp.h +++ b/libvips/foreign/webp.h @@ -49,9 +49,9 @@ int vips__webp_read_buffer( const void *buf, size_t len, VipsImage *out, int shrink ); int vips__webp_write_file( VipsImage *out, const char *filename, - int Q, gboolean lossless ); + int Q, gboolean lossless, VipsForeignWebpPreset preset ); int vips__webp_write_buffer( VipsImage *out, void **buf, size_t *len, - int Q, gboolean lossless ); + int Q, gboolean lossless, VipsForeignWebpPreset preset ); #ifdef __cplusplus } diff --git a/libvips/foreign/webpsave.c b/libvips/foreign/webpsave.c index b507785a..2b411d21 100644 --- a/libvips/foreign/webpsave.c +++ b/libvips/foreign/webpsave.c @@ -60,6 +60,10 @@ typedef struct _VipsForeignSaveWebp { */ gboolean lossless; + /* Lossy compression preset. + */ + VipsForeignWebpPreset preset; + } VipsForeignSaveWebp; typedef VipsForeignSaveClass VipsForeignSaveWebpClass; @@ -109,6 +113,14 @@ vips_foreign_save_webp_class_init( VipsForeignSaveWebpClass *class ) G_STRUCT_OFFSET( VipsForeignSaveWebp, lossless ), FALSE ); + VIPS_ARG_ENUM( class, "preset", 12, + _( "preset" ), + _( "Preset for lossy compression" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsForeignSaveWebp, preset ), + VIPS_TYPE_FOREIGN_WEBP_PRESET, + VIPS_FOREIGN_WEBP_PRESET_DEFAULT ); + } static void @@ -143,7 +155,7 @@ vips_foreign_save_webp_file_build( VipsObject *object ) return( -1 ); if( vips__webp_write_file( save->ready, file->filename, - webp->Q, webp->lossless ) ) + webp->Q, webp->lossless, webp->preset ) ) return( -1 ); return( 0 ); @@ -205,7 +217,7 @@ vips_foreign_save_webp_buffer_build( VipsObject *object ) return( -1 ); if( vips__webp_write_buffer( save->ready, &obuf, &olen, - webp->Q, webp->lossless ) ) + webp->Q, webp->lossless, webp->preset ) ) return( -1 ); blob = vips_blob_new( (VipsCallbackFn) vips_free, obuf, olen ); @@ -266,7 +278,7 @@ vips_foreign_save_webp_mime_build( VipsObject *object ) return( -1 ); if( vips__webp_write_buffer( save->ready, &obuf, &olen, - webp->Q, webp->lossless ) ) + webp->Q, webp->lossless, webp->preset ) ) return( -1 ); printf( "Content-length: %zu\r\n", olen ); diff --git a/libvips/include/vips/enumtypes.h b/libvips/include/vips/enumtypes.h index 8fdc127a..f1b132fc 100644 --- a/libvips/include/vips/enumtypes.h +++ b/libvips/include/vips/enumtypes.h @@ -14,6 +14,8 @@ GType vips_foreign_flags_get_type (void) G_GNUC_CONST; #define VIPS_TYPE_FOREIGN_FLAGS (vips_foreign_flags_get_type()) GType vips_saveable_get_type (void) G_GNUC_CONST; #define VIPS_TYPE_SAVEABLE (vips_saveable_get_type()) +GType vips_foreign_webp_preset_get_type (void) G_GNUC_CONST; +#define VIPS_TYPE_FOREIGN_WEBP_PRESET (vips_foreign_webp_preset_get_type()) GType vips_foreign_tiff_compression_get_type (void) G_GNUC_CONST; #define VIPS_TYPE_FOREIGN_TIFF_COMPRESSION (vips_foreign_tiff_compression_get_type()) GType vips_foreign_tiff_predictor_get_type (void) G_GNUC_CONST; diff --git a/libvips/include/vips/foreign.h b/libvips/include/vips/foreign.h index 36328f43..a3a9af8e 100644 --- a/libvips/include/vips/foreign.h +++ b/libvips/include/vips/foreign.h @@ -338,6 +338,29 @@ int vips_jpegsave_buffer( VipsImage *in, void **buf, size_t *len, ... ) int vips_jpegsave_mime( VipsImage *in, ... ) __attribute__((sentinel)); +/** + * VipsForeignWebpPreset: + * @VIPS_FOREIGN_WEBP_PRESET_DEFAULT: default preset + * @VIPS_FOREIGN_WEBP_PRESET_PICTURE: digital picture, like portrait, + * inner shot + * @VIPS_FOREIGN_WEBP_PRESET_PHOTO: outdoor photograph, with natural lighting + * @VIPS_FOREIGN_WEBP_PRESET_DRAWING: hand or line drawing, with high-contrast + * details + * @VIPS_FOREIGN_WEBP_PRESET_ICON: small-sized colorful images + * @VIPS_FOREIGN_WEBP_PRESET_TEXT: text-like + * + * Tune lossy encoder settings for different image types. + */ +typedef enum { + VIPS_FOREIGN_WEBP_PRESET_DEFAULT, + VIPS_FOREIGN_WEBP_PRESET_PICTURE, + VIPS_FOREIGN_WEBP_PRESET_PHOTO, + VIPS_FOREIGN_WEBP_PRESET_DRAWING, + VIPS_FOREIGN_WEBP_PRESET_ICON, + VIPS_FOREIGN_WEBP_PRESET_TEXT, + VIPS_FOREIGN_WEBP_PRESET_LAST +} VipsForeignWebpPreset; + int vips_webpload( const char *filename, VipsImage **out, ... ) __attribute__((sentinel)); int vips_webpload_buffer( void *buf, size_t len, VipsImage **out, ... ) diff --git a/libvips/iofuncs/enumtypes.c b/libvips/iofuncs/enumtypes.c index 4fb8062f..93f4564e 100644 --- a/libvips/iofuncs/enumtypes.c +++ b/libvips/iofuncs/enumtypes.c @@ -70,6 +70,28 @@ vips_saveable_get_type( void ) return( etype ); } GType +vips_foreign_webp_preset_get_type( void ) +{ + static GType etype = 0; + + if( etype == 0 ) { + static const GEnumValue values[] = { + {VIPS_FOREIGN_WEBP_PRESET_DEFAULT, "VIPS_FOREIGN_WEBP_PRESET_DEFAULT", "default"}, + {VIPS_FOREIGN_WEBP_PRESET_PICTURE, "VIPS_FOREIGN_WEBP_PRESET_PICTURE", "picture"}, + {VIPS_FOREIGN_WEBP_PRESET_PHOTO, "VIPS_FOREIGN_WEBP_PRESET_PHOTO", "photo"}, + {VIPS_FOREIGN_WEBP_PRESET_DRAWING, "VIPS_FOREIGN_WEBP_PRESET_DRAWING", "drawing"}, + {VIPS_FOREIGN_WEBP_PRESET_ICON, "VIPS_FOREIGN_WEBP_PRESET_ICON", "icon"}, + {VIPS_FOREIGN_WEBP_PRESET_TEXT, "VIPS_FOREIGN_WEBP_PRESET_TEXT", "text"}, + {VIPS_FOREIGN_WEBP_PRESET_LAST, "VIPS_FOREIGN_WEBP_PRESET_LAST", "last"}, + {0, NULL, NULL} + }; + + etype = g_enum_register_static( "VipsForeignWebpPreset", values ); + } + + return( etype ); +} +GType vips_foreign_tiff_compression_get_type( void ) { static GType etype = 0;