Add lossy compression "preset" option to webpsave

This allows to tune the lossy webp encoder for certain types of images.
This commit is contained in:
Felix Bünemann 2016-04-22 19:54:19 +02:00
parent 7f70abd4ba
commit f834ea39f6
7 changed files with 100 additions and 11 deletions

View File

@ -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().
*

View File

@ -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;

View File

@ -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
}

View File

@ -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 );

View File

@ -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;

View File

@ -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, ... )

View File

@ -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;