Merge pull request #430 from felixbuenemann/use-webp-advanced-encoding-api
Use WebP Advanced Encoding API and make it tunable
This commit is contained in:
commit
c88b94cb29
@ -677,7 +677,7 @@ AC_ARG_WITH([libwebp],
|
||||
AS_HELP_STRING([--without-libwebp], [build without libwebp (default: test)]))
|
||||
|
||||
if test x"$with_libwebp" != "xno"; then
|
||||
PKG_CHECK_MODULES(LIBWEBP, libwebp,
|
||||
PKG_CHECK_MODULES(LIBWEBP, libwebp >= 0.1.3,
|
||||
[AC_DEFINE(HAVE_LIBWEBP,1,[define if you have libwebp installed.])
|
||||
with_libwebp=yes
|
||||
PACKAGES_USED="$PACKAGES_USED libwebp"],
|
||||
@ -966,6 +966,7 @@ SVG import with librsvg-2.0: $with_rsvg
|
||||
(requires librsvg-2.0 2.40.0 or later)
|
||||
file import with cfitsio: $with_cfitsio
|
||||
file import/export with libwebp: $with_libwebp
|
||||
(requires libwebp-0.1.3 or later)
|
||||
text rendering with pangoft2: $with_pangoft2
|
||||
file import/export with libpng: $with_png
|
||||
(requires libpng-1.2.9 or later)
|
||||
|
@ -2458,6 +2458,11 @@ 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
|
||||
* @smart_subsample: enables high quality chroma subsampling
|
||||
* @near_lossless: use preprocessing in lossless mode (controlled by Q)
|
||||
* @alpha_q: set alpha quality in lossless mode
|
||||
*
|
||||
* See also: vips_webpload(), vips_image_write_to_file().
|
||||
*
|
||||
@ -2486,6 +2491,17 @@ vips_webpsave( VipsImage *in, const char *filename, ... )
|
||||
* Optional arguments:
|
||||
*
|
||||
* @Q: JPEG quality factor
|
||||
* @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)
|
||||
* @alpha_q: set alpha quality in lossless mode
|
||||
*
|
||||
* As vips_webpsave(), but save to a memory buffer.
|
||||
*
|
||||
* The address of the buffer is returned in @obuf, the length of the buffer in
|
||||
* @olen. You are responsible for freeing the buffer with g_free() when you
|
||||
* are done with it. The buffer is freed for you on error.
|
||||
*
|
||||
* See also: vips_webpsave().
|
||||
*
|
||||
|
@ -46,6 +46,7 @@
|
||||
#ifdef HAVE_LIBWEBP
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
|
||||
@ -53,125 +54,160 @@
|
||||
|
||||
#include "webp.h"
|
||||
|
||||
typedef size_t (*webp_encoder)( const uint8_t *rgb,
|
||||
int width, int height, int stride,
|
||||
float quality_factor, uint8_t **output );
|
||||
typedef int (*webp_import)( WebPPicture *picture,
|
||||
const uint8_t *rgb, int stride );
|
||||
|
||||
typedef size_t (*webp_encoder_lossless)( const uint8_t *rgb,
|
||||
int width, int height, int stride, uint8_t **output );
|
||||
|
||||
int
|
||||
vips__webp_write_file( VipsImage *in, const char *filename,
|
||||
int Q, gboolean lossless )
|
||||
static WebPPreset
|
||||
get_preset( VipsForeignWebpPreset preset )
|
||||
{
|
||||
VipsImage *memory;
|
||||
size_t len;
|
||||
uint8_t *buffer;
|
||||
FILE *fp;
|
||||
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 );
|
||||
|
||||
if( !(memory = vips_image_copy_memory( in )) )
|
||||
return( -1 );
|
||||
|
||||
if( lossless ) {
|
||||
webp_encoder_lossless encoder;
|
||||
|
||||
if( in->Bands == 4 )
|
||||
encoder = WebPEncodeLosslessRGBA;
|
||||
else
|
||||
encoder = WebPEncodeLosslessRGB;
|
||||
|
||||
if( !(len = encoder( VIPS_IMAGE_ADDR( memory, 0, 0 ),
|
||||
memory->Xsize, memory->Ysize,
|
||||
VIPS_IMAGE_SIZEOF_LINE( memory ),
|
||||
&buffer )) ) {
|
||||
VIPS_UNREF( memory );
|
||||
vips_error( "vips2webp",
|
||||
"%s", _( "unable to encode" ) );
|
||||
return( -1 );
|
||||
}
|
||||
}
|
||||
else {
|
||||
webp_encoder encoder;
|
||||
|
||||
if( in->Bands == 4 )
|
||||
encoder = WebPEncodeRGBA;
|
||||
else
|
||||
encoder = WebPEncodeRGB;
|
||||
|
||||
if( !(len = encoder( VIPS_IMAGE_ADDR( memory, 0, 0 ),
|
||||
memory->Xsize, memory->Ysize,
|
||||
VIPS_IMAGE_SIZEOF_LINE( memory ),
|
||||
Q, &buffer )) ) {
|
||||
VIPS_UNREF( memory );
|
||||
vips_error( "vips2webp",
|
||||
"%s", _( "unable to encode" ) );
|
||||
return( -1 );
|
||||
}
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
VIPS_UNREF( memory );
|
||||
|
||||
if( !(fp = vips__file_open_write( filename, FALSE )) ) {
|
||||
free( buffer );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( vips__file_write( buffer, len, 1, fp ) ) {
|
||||
fclose( fp );
|
||||
free( buffer );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
fclose( fp );
|
||||
free( buffer );
|
||||
|
||||
return( 0 );
|
||||
/* Keep -Wall happy.
|
||||
*/
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
int
|
||||
vips__webp_write_buffer( VipsImage *in, void **obuf, size_t *olen,
|
||||
int Q, gboolean lossless )
|
||||
typedef struct {
|
||||
uint8_t *mem;
|
||||
size_t size;
|
||||
size_t max_size;
|
||||
} VipsWebPMemoryWriter;
|
||||
|
||||
static void
|
||||
init_memory_writer( VipsWebPMemoryWriter *writer ) {
|
||||
writer->mem = NULL;
|
||||
writer->size = 0;
|
||||
writer->max_size = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
memory_write( const uint8_t *data, size_t data_size,
|
||||
const WebPPicture *picture ) {
|
||||
VipsWebPMemoryWriter* const w = (VipsWebPMemoryWriter*) picture->custom_ptr;
|
||||
size_t next_size;
|
||||
|
||||
if( w == NULL )
|
||||
return( 0 );
|
||||
|
||||
next_size = w->size + data_size;
|
||||
|
||||
if( next_size > w->max_size ) {
|
||||
uint8_t *new_mem;
|
||||
const size_t next_max_size =
|
||||
VIPS_MAX( 8192, VIPS_MAX( next_size, w->max_size * 2 ) );
|
||||
|
||||
new_mem = (uint8_t*) g_try_malloc( next_max_size );
|
||||
if( new_mem == NULL )
|
||||
return( 0 );
|
||||
|
||||
if( w->size > 0 )
|
||||
memcpy( new_mem, w->mem, w->size );
|
||||
|
||||
g_free( w->mem );
|
||||
w->mem = new_mem;
|
||||
w->max_size = next_max_size;
|
||||
}
|
||||
|
||||
if( data_size > 0 ) {
|
||||
memcpy( w->mem + w->size, data, data_size );
|
||||
w->size += data_size;
|
||||
}
|
||||
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
static int
|
||||
write_webp( WebPPicture *pic, VipsImage *in,
|
||||
int Q, gboolean lossless, VipsForeignWebpPreset preset,
|
||||
gboolean smart_subsample, gboolean near_lossless,
|
||||
int alpha_q )
|
||||
{
|
||||
VipsImage *memory;
|
||||
WebPConfig config;
|
||||
webp_import import;
|
||||
|
||||
if ( !WebPConfigPreset(&config, get_preset( preset ), Q) ) {
|
||||
vips_error( "vips2webp",
|
||||
"%s", _( "config version error" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
#if WEBP_ENCODER_ABI_VERSION >= 0x0100
|
||||
config.lossless = lossless || near_lossless;
|
||||
config.alpha_quality = alpha_q;
|
||||
/* Smart subsampling requires use_argb because
|
||||
* it is applied during RGB to YUV conversion.
|
||||
*/
|
||||
pic->use_argb = lossless || near_lossless || smart_subsample;
|
||||
#else
|
||||
if( lossless || near_lossless )
|
||||
vips_warn( "vips2webp",
|
||||
"%s", _( "lossless unsupported" ) );
|
||||
if( alpha_q != 100 )
|
||||
vips_warn( "vips2webp",
|
||||
"%s", _( "alpha_q unsupported" ) );
|
||||
#endif
|
||||
|
||||
#if WEBP_ENCODER_ABI_VERSION >= 0x0209
|
||||
if( near_lossless )
|
||||
config.near_lossless = Q;
|
||||
if( smart_subsample )
|
||||
config.preprocessing |= 4;
|
||||
#else
|
||||
if( near_lossless )
|
||||
vips_warn( "vips2webp",
|
||||
"%s", _( "near_lossless unsupported" ) );
|
||||
if( smart_subsample )
|
||||
vips_warn( "vips2webp",
|
||||
"%s", _( "smart_subsample unsupported" ) );
|
||||
#endif
|
||||
|
||||
if( !WebPValidateConfig(&config) ) {
|
||||
vips_error( "vips2webp",
|
||||
"%s", _( "invalid configuration" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( !(memory = vips_image_copy_memory( in )) )
|
||||
return( -1 );
|
||||
|
||||
if( lossless ) {
|
||||
webp_encoder_lossless encoder;
|
||||
pic->width = memory->Xsize;
|
||||
pic->height = memory->Ysize;
|
||||
|
||||
if( in->Bands == 4 )
|
||||
encoder = WebPEncodeLosslessRGBA;
|
||||
else
|
||||
encoder = WebPEncodeLosslessRGB;
|
||||
if( in->Bands == 4 )
|
||||
import = WebPPictureImportRGBA;
|
||||
else
|
||||
import = WebPPictureImportRGB;
|
||||
|
||||
if( !(*olen = encoder( VIPS_IMAGE_ADDR( memory, 0, 0 ),
|
||||
memory->Xsize, memory->Ysize,
|
||||
VIPS_IMAGE_SIZEOF_LINE( memory ),
|
||||
(uint8_t **) obuf )) ) {
|
||||
VIPS_UNREF( memory );
|
||||
vips_error( "vips2webp",
|
||||
"%s", _( "unable to encode" ) );
|
||||
return( -1 );
|
||||
}
|
||||
if( !import( pic, VIPS_IMAGE_ADDR( memory, 0, 0 ),
|
||||
VIPS_IMAGE_SIZEOF_LINE( memory ) ) ) {
|
||||
VIPS_UNREF( memory );
|
||||
vips_error( "vips2webp",
|
||||
"%s", _( "picture memory error" ) );
|
||||
return( -1 );
|
||||
}
|
||||
else {
|
||||
webp_encoder encoder;
|
||||
|
||||
if( in->Bands == 4 )
|
||||
encoder = WebPEncodeRGBA;
|
||||
else
|
||||
encoder = WebPEncodeRGB;
|
||||
|
||||
if( !(*olen = encoder( VIPS_IMAGE_ADDR( memory, 0, 0 ),
|
||||
memory->Xsize, memory->Ysize,
|
||||
VIPS_IMAGE_SIZEOF_LINE( memory ),
|
||||
Q, (uint8_t **) obuf )) ) {
|
||||
VIPS_UNREF( memory );
|
||||
vips_error( "vips2webp",
|
||||
"%s", _( "unable to encode" ) );
|
||||
return( -1 );
|
||||
}
|
||||
if( !WebPEncode( &config, pic ) ) {
|
||||
VIPS_UNREF( memory );
|
||||
vips_error( "vips2webp",
|
||||
"%s", _( "unable to encode" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
VIPS_UNREF( memory );
|
||||
@ -179,4 +215,85 @@ vips__webp_write_buffer( VipsImage *in, void **obuf, size_t *olen,
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
vips__webp_write_file( VipsImage *in, const char *filename,
|
||||
int Q, gboolean lossless, VipsForeignWebpPreset preset,
|
||||
gboolean smart_subsample, gboolean near_lossless,
|
||||
int alpha_q )
|
||||
{
|
||||
WebPPicture pic;
|
||||
VipsWebPMemoryWriter writer;
|
||||
FILE *fp;
|
||||
|
||||
if( !WebPPictureInit( &pic ) ) {
|
||||
vips_error( "vips2webp",
|
||||
"%s", _( "picture version error" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
init_memory_writer( &writer );
|
||||
pic.writer = memory_write;
|
||||
pic.custom_ptr = &writer;
|
||||
|
||||
if( write_webp( &pic, in, Q, lossless, preset, smart_subsample,
|
||||
near_lossless, alpha_q ) ) {
|
||||
WebPPictureFree( &pic );
|
||||
g_free( writer.mem );
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebPPictureFree( &pic );
|
||||
|
||||
if( !(fp = vips__file_open_write( filename, FALSE )) ) {
|
||||
g_free( writer.mem );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( vips__file_write( writer.mem, writer.size, 1, fp ) ) {
|
||||
fclose( fp );
|
||||
g_free( writer.mem );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
fclose( fp );
|
||||
g_free( writer.mem );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
vips__webp_write_buffer( VipsImage *in, void **obuf, size_t *olen,
|
||||
int Q, gboolean lossless, VipsForeignWebpPreset preset,
|
||||
gboolean smart_subsample, gboolean near_lossless,
|
||||
int alpha_q )
|
||||
{
|
||||
WebPPicture pic;
|
||||
VipsWebPMemoryWriter writer;
|
||||
FILE *fp;
|
||||
|
||||
if( !WebPPictureInit( &pic ) ) {
|
||||
vips_error( "vips2webp",
|
||||
"%s", _( "picture version error" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
init_memory_writer( &writer );
|
||||
pic.writer = memory_write;
|
||||
pic.custom_ptr = &writer;
|
||||
|
||||
if( write_webp( &pic, in, Q, lossless, preset, smart_subsample,
|
||||
near_lossless, alpha_q ) ) {
|
||||
WebPPictureFree( &pic );
|
||||
g_free( writer.mem );
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebPPictureFree( &pic );
|
||||
|
||||
*obuf = writer.mem;
|
||||
*olen = writer.size;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
#endif /*HAVE_LIBWEBP*/
|
||||
|
@ -49,9 +49,13 @@ 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,
|
||||
gboolean smart_subsample, gboolean near_lossless,
|
||||
int alpha_q );
|
||||
int vips__webp_write_buffer( VipsImage *out, void **buf, size_t *len,
|
||||
int Q, gboolean lossless );
|
||||
int Q, gboolean lossless, VipsForeignWebpPreset preset,
|
||||
gboolean smart_subsample, gboolean near_lossless,
|
||||
int alpha_q );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -60,6 +60,22 @@ typedef struct _VipsForeignSaveWebp {
|
||||
*/
|
||||
gboolean lossless;
|
||||
|
||||
/* Lossy compression preset.
|
||||
*/
|
||||
VipsForeignWebpPreset preset;
|
||||
|
||||
/* Enable smart chroma subsampling.
|
||||
*/
|
||||
gboolean smart_subsample;
|
||||
|
||||
/* Use preprocessing in lossless mode.
|
||||
*/
|
||||
gboolean near_lossless;
|
||||
|
||||
/* Alpha quality.
|
||||
*/
|
||||
int alpha_q;
|
||||
|
||||
} VipsForeignSaveWebp;
|
||||
|
||||
typedef VipsForeignSaveClass VipsForeignSaveWebpClass;
|
||||
@ -100,7 +116,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" ),
|
||||
@ -109,12 +125,41 @@ 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 );
|
||||
|
||||
VIPS_ARG_BOOL( class, "smart_subsample", 13,
|
||||
_( "Smart subsampling" ),
|
||||
_( "Enable high quality chroma subsampling" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
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 );
|
||||
|
||||
VIPS_ARG_INT( class, "alpha_q", 15,
|
||||
_( "Alpha quality" ),
|
||||
_( "Change alpha plane fidelity for lossy compression" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsForeignSaveWebp, alpha_q ),
|
||||
0, 100, 100 );
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_save_webp_init( VipsForeignSaveWebp *webp )
|
||||
{
|
||||
webp->Q = 80;
|
||||
webp->Q = 75;
|
||||
}
|
||||
|
||||
typedef struct _VipsForeignSaveWebpFile {
|
||||
@ -143,7 +188,9 @@ 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,
|
||||
webp->smart_subsample, webp->near_lossless,
|
||||
webp->alpha_q ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
@ -205,7 +252,9 @@ 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,
|
||||
webp->smart_subsample, webp->near_lossless,
|
||||
webp->alpha_q ) )
|
||||
return( -1 );
|
||||
|
||||
blob = vips_blob_new( (VipsCallbackFn) vips_free, obuf, olen );
|
||||
@ -266,7 +315,9 @@ 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,
|
||||
webp->smart_subsample, webp->near_lossless,
|
||||
webp->alpha_q ) )
|
||||
return( -1 );
|
||||
|
||||
printf( "Content-length: %zu\r\n", olen );
|
||||
|
@ -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;
|
||||
|
@ -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, ... )
|
||||
|
@ -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;
|
||||
|
@ -186,6 +186,10 @@ fi
|
||||
if test_supported jpegload; then
|
||||
test_format $image jpg 90
|
||||
fi
|
||||
if test_supported webpload; then
|
||||
test_format $image webp 90
|
||||
test_format $image webp 0 [lossless]
|
||||
fi
|
||||
test_format $image ppm 0
|
||||
test_format $image pfm 0
|
||||
if test_supported fitsload; then
|
||||
@ -220,4 +224,3 @@ if test_supported dzsave; then
|
||||
test_saver copy $image .dz
|
||||
test_saver copy $image .dz[container=zip]
|
||||
fi
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user