add webp shrink-on-load
and vipsthumbnail knows about it too see https://github.com/jcupitt/libvips/issues/398
This commit is contained in:
parent
e582f13d13
commit
19a838470b
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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 );
|
||||
|
@ -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 );
|
||||
|
@ -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 );
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user