add webp shrink-on-load

and vipsthumbnail knows about it too

see https://github.com/jcupitt/libvips/issues/398
This commit is contained in:
John Cupitt 2016-02-28 14:36:21 +00:00
parent e582f13d13
commit 19a838470b
7 changed files with 113 additions and 34 deletions

View File

@ -13,6 +13,8 @@
- better handling of deprecated args in python
- much better handling of arrayimage command-line args
- faster hist_find (Lovell Fuller)
- webpload has a @shrink parameter for shrink-on-load
- vipsthumbnail knows about webp shrink-on-load
27/1/16 started 8.2.3
- fix a crash with SPARC byte-order labq vips images

View File

@ -51,11 +51,11 @@ webp2vips( const char *name, IMAGE *out, gboolean header_only )
#ifdef HAVE_LIBWEBP
if( header_only ) {
if( vips__webp_read_file_header( filename, out ) )
if( vips__webp_read_file_header( filename, out, 1 ) )
return( -1 );
}
else {
if( vips__webp_read_file( filename, out ) )
if( vips__webp_read_file( filename, out, 1 ) )
return( -1 );
}
#else

View File

@ -2372,8 +2372,14 @@ vips_jpegsave_mime( VipsImage *in, ... )
* @out: decompressed image
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* @shrink: %gint, shrink by this much on load
*
* Read a WebP file into a VIPS image.
*
* Use @shrink to specify a shrink-on-load factor.
*
* See also: vips_image_new_from_file().
*
* Returns: 0 on success, -1 on error.
@ -2398,6 +2404,10 @@ vips_webpload( const char *filename, VipsImage **out, ... )
* @out: image to write
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* @shrink: %gint, shrink by this much on load
*
* Read a WebP-formatted memory block into a VIPS image. Exactly as
* vips_webpload(), but read from a memory buffer.
*

View File

@ -40,13 +40,13 @@ extern const char *vips__webp_suffs[];
int vips__iswebp_buffer( const void *buf, size_t len );
int vips__iswebp( const char *filename );
int vips__webp_read_file_header( const char *name, VipsImage *out );
int vips__webp_read_file( const char *name, VipsImage *out );
int vips__webp_read_file_header( const char *name, VipsImage *out, int shrink );
int vips__webp_read_file( const char *name, VipsImage *out, int shrink );
int vips__webp_read_buffer_header( const void *buf, size_t len,
VipsImage *out );
VipsImage *out, int shrink );
int vips__webp_read_buffer( const void *buf, size_t len,
VipsImage *out );
VipsImage *out, int shrink );
int vips__webp_write_file( VipsImage *out, const char *filename,
int Q, gboolean lossless );

View File

@ -4,6 +4,8 @@
* - from png2vips.c
* 24/2/14
* - oops, buffer path was broken, thanks Lovell
* 28/2/16
* - add @shrink
*/
/*
@ -75,6 +77,15 @@ typedef struct {
const void *data;
gint64 length;
/* Shrink-on-load factor. Use this to set scaled_width.
*/
int shrink;
/* Size we are decoding to.
*/
int width;
int height;
/* If we are opening a file object, the fd.
*/
int fd;
@ -132,7 +143,7 @@ read_free( Read *read )
}
static Read *
read_new( const char *filename, const void *data, size_t length )
read_new( const char *filename, const void *data, size_t length, int shrink )
{
Read *read;
@ -142,6 +153,7 @@ read_new( const char *filename, const void *data, size_t length )
read->filename = g_strdup( filename );
read->data = data;
read->length = length;
read->shrink = shrink;
read->fd = 0;
read->idec = NULL;
@ -171,7 +183,23 @@ read_new( const char *filename, const void *data, size_t length )
read->config.output.colorspace = MODE_RGBA;
else
read->config.output.colorspace = MODE_RGB;
read->config.options.use_threads = TRUE;
read->config.options.use_threads = 1;
read->width = read->config.input.width / read->shrink;
read->height = read->config.input.height / read->shrink;
if( read->width == 0 ||
read->height == 0 ) {
vips_error( "webp", "%s", _( "bad setting for shrink" ) );
return( NULL );
}
if( read->shrink > 1 ) {
read->config.options.use_scaling = 1;
read->config.options.scaled_width = read->width;
read->config.options.scaled_height = read->height;
}
return( read );
}
@ -180,7 +208,7 @@ static int
read_header( Read *read, VipsImage *out )
{
vips_image_init_fields( out,
read->config.input.width, read->config.input.height,
read->width, read->height,
read->config.input.has_alpha ? 4 : 3,
VIPS_FORMAT_UCHAR, VIPS_CODING_NONE,
VIPS_INTERPRETATION_sRGB,
@ -192,11 +220,11 @@ read_header( Read *read, VipsImage *out )
}
int
vips__webp_read_file_header( const char *filename, VipsImage *out )
vips__webp_read_file_header( const char *filename, VipsImage *out, int shrink )
{
Read *read;
if( !(read = read_new( filename, NULL, 0 )) ) {
if( !(read = read_new( filename, NULL, 0, shrink )) ) {
vips_error( "webp2vips",
_( "unable to open \"%s\"" ), filename );
return( -1 );
@ -210,16 +238,11 @@ vips__webp_read_file_header( const char *filename, VipsImage *out )
return( 0 );
}
typedef uint8_t *(*webp_decoder)( const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size,
int output_stride );
static int
read_image( Read *read, VipsImage *out )
{
VipsImage **t = (VipsImage **)
vips_object_local_array( VIPS_OBJECT( out ), 3 );
webp_decoder decoder;
t[0] = vips_image_new_memory();
if( read_header( read, t[0] ) )
@ -227,15 +250,13 @@ read_image( Read *read, VipsImage *out )
if( vips_image_write_prepare( t[0] ) )
return( -1 );
if( t[0]->Bands == 3 )
decoder = WebPDecodeRGBInto;
else
decoder = WebPDecodeRGBAInto;
read->config.output.u.RGBA.rgba = VIPS_IMAGE_ADDR( t[0], 0, 0 );
read->config.output.u.RGBA.stride = VIPS_IMAGE_SIZEOF_LINE( t[0] );
read->config.output.u.RGBA.size = VIPS_IMAGE_SIZEOF_IMAGE( t[0] );
read->config.output.is_external_memory = 1;
if( !decoder( (uint8_t *) read->data, read->length,
VIPS_IMAGE_ADDR( t[0], 0, 0 ),
VIPS_IMAGE_SIZEOF_IMAGE( t[0] ),
VIPS_IMAGE_SIZEOF_LINE( t[0] ) ) ) {
if( WebPDecode( (uint8_t *) read->data, read->length,
&read->config) != VP8_STATUS_OK ) {
vips_error( "webp2vips", "%s", _( "unable to read pixels" ) );
return( -1 );
}
@ -247,11 +268,11 @@ read_image( Read *read, VipsImage *out )
}
int
vips__webp_read_file( const char *filename, VipsImage *out )
vips__webp_read_file( const char *filename, VipsImage *out, int shrink )
{
Read *read;
if( !(read = read_new( filename, NULL, 0 )) ) {
if( !(read = read_new( filename, NULL, 0, shrink )) ) {
vips_error( "webp2vips",
_( "unable to open \"%s\"" ), filename );
return( -1 );
@ -266,11 +287,12 @@ vips__webp_read_file( const char *filename, VipsImage *out )
}
int
vips__webp_read_buffer_header( const void *buf, size_t len, VipsImage *out )
vips__webp_read_buffer_header( const void *buf, size_t len, VipsImage *out,
int shrink )
{
Read *read;
if( !(read = read_new( NULL, buf, len )) ) {
if( !(read = read_new( NULL, buf, len, shrink )) ) {
vips_error( "webp2vips",
"%s", _( "unable to open buffer" ) );
return( -1 );
@ -285,11 +307,12 @@ vips__webp_read_buffer_header( const void *buf, size_t len, VipsImage *out )
}
int
vips__webp_read_buffer( const void *buf, size_t len, VipsImage *out )
vips__webp_read_buffer( const void *buf, size_t len, VipsImage *out,
int shrink )
{
Read *read;
if( !(read = read_new( NULL, buf, len )) ) {
if( !(read = read_new( NULL, buf, len, shrink )) ) {
vips_error( "webp2vips",
"%s", _( "unable to open buffer" ) );
return( -1 );

View File

@ -2,6 +2,8 @@
*
* 6/8/13
* - from pngload.c
* 28/2/16
* - add @shrink
*/
/*
@ -52,6 +54,9 @@
typedef struct _VipsForeignLoadWebp {
VipsForeignLoad parent_object;
/* Shrink by this much during load.
*/
int shrink;
} VipsForeignLoadWebp;
typedef VipsForeignLoadClass VipsForeignLoadWebpClass;
@ -91,11 +96,19 @@ vips_foreign_load_webp_class_init( VipsForeignLoadWebpClass *class )
load_class->get_flags = vips_foreign_load_webp_get_flags;
VIPS_ARG_INT( class, "shrink", 10,
_( "Shrink" ),
_( "Shrink factor on load" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadWebp, shrink ),
1, 1024, 1 );
}
static void
vips_foreign_load_webp_init( VipsForeignLoadWebp *webp )
{
webp->shrink = 1;
}
typedef struct _VipsForeignLoadWebpFile {
@ -127,9 +140,11 @@ vips_foreign_load_webp_file_is_a( const char *filename )
static int
vips_foreign_load_webp_file_header( VipsForeignLoad *load )
{
VipsForeignLoadWebp *webp = (VipsForeignLoadWebp *) load;
VipsForeignLoadWebpFile *file = (VipsForeignLoadWebpFile *) load;
if( vips__webp_read_file_header( file->filename, load->out ) )
if( vips__webp_read_file_header( file->filename, load->out,
webp->shrink ) )
return( -1 );
VIPS_SETSTR( load->out->filename, file->filename );
@ -140,9 +155,10 @@ vips_foreign_load_webp_file_header( VipsForeignLoad *load )
static int
vips_foreign_load_webp_file_load( VipsForeignLoad *load )
{
VipsForeignLoadWebp *webp = (VipsForeignLoadWebp *) load;
VipsForeignLoadWebpFile *file = (VipsForeignLoadWebpFile *) load;
if( vips__webp_read_file( file->filename, load->real ) )
if( vips__webp_read_file( file->filename, load->real, webp->shrink ) )
return( -1 );
return( 0 );
@ -202,10 +218,11 @@ G_DEFINE_TYPE( VipsForeignLoadWebpBuffer, vips_foreign_load_webp_buffer,
static int
vips_foreign_load_webp_buffer_header( VipsForeignLoad *load )
{
VipsForeignLoadWebp *webp = (VipsForeignLoadWebp *) load;
VipsForeignLoadWebpBuffer *buffer = (VipsForeignLoadWebpBuffer *) load;
if( vips__webp_read_buffer_header( buffer->buf->data,
buffer->buf->length, load->out ) )
buffer->buf->length, load->out, webp->shrink ) )
return( -1 );
return( 0 );
@ -214,10 +231,11 @@ vips_foreign_load_webp_buffer_header( VipsForeignLoad *load )
static int
vips_foreign_load_webp_buffer_load( VipsForeignLoad *load )
{
VipsForeignLoadWebp *webp = (VipsForeignLoadWebp *) load;
VipsForeignLoadWebpBuffer *buffer = (VipsForeignLoadWebpBuffer *) load;
if( vips__webp_read_buffer( buffer->buf->data, buffer->buf->length,
load->real ) )
load->real, webp->shrink ) )
return( -1 );
return( 0 );

View File

@ -73,6 +73,8 @@
* 9/2/16
* - add PDF --size support
* - add SVG --size support
* 28/2/16
* - add webp --shrink support
*/
#ifdef HAVE_CONFIG_H
@ -327,6 +329,30 @@ thumbnail_open( VipsObject *process, const char *filename )
return( NULL );
}
else if( strcmp( loader, "VipsForeignLoadWebpFile" ) == 0 ) {
double shrink;
/* This will just read in the header and is quick.
*/
if( !(im = vips_image_new_from_file( filename, NULL )) )
return( NULL );
shrink = calculate_shrink( im );
g_object_unref( im );
vips_info( "vipsthumbnail",
"loading webp with factor %g pre-shrink",
shrink );
/* We can't use UNBUFERRED safely on very-many-core systems.
*/
if( !(im = vips_image_new_from_file( filename,
"access", VIPS_ACCESS_SEQUENTIAL,
"shrink", (int) shrink,
NULL )) )
return( NULL );
}
else {
/* All other formats. We can't use UNBUFERRED safely on
* very-many-core systems.