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:
parent
58a2616f77
commit
c107066c4e
@ -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().
|
||||||
*
|
*
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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 );
|
||||||
|
Loading…
Reference in New Issue
Block a user