basic webp load done

This commit is contained in:
John Cupitt 2013-08-06 15:51:23 +01:00
parent 878c196341
commit 165e7c9717
4 changed files with 198 additions and 14 deletions

View File

@ -7,6 +7,7 @@
- added vips_error_freeze() / vips_error_thaw()
- used freeze() / thaw() to stop file format sniffers logging spurious errors
- vipsthumbnail uses embedded jpg thumbnails if it can
- added vips_webpload(), vips_webpload_buffer()
3/7/13 started 7.34.2
- lower priority for Matlab load to reduce segvs from Mat_Open(), thanks

View File

@ -689,14 +689,14 @@ fi
# Gather all up for VIPS_CFLAGS, VIPS_INCLUDES, VIPS_LIBS and VIPS_CXX_LIBS
# sort includes to get longer, more specific dirs first
# helps, for example, selecting graphicsmagick over imagemagick
VIPS_CFLAGS=`for i in $VIPS_CFLAGS $GTHREAD_CFLAGS $REQUIRED_CFLAGS $PANGOFT2_CFLAGS $FFTW_CFLAGS $MAGICK_CFLAGS $PNG_CFLAGS $EXIF_CFLAGS $MATIO_CFLAGS $CFITSIO_CFLAGS $OPENEXR_CFLAGS $OPENSLIDE_CFLAGS $ORC_CFLAGS $TIFF_CFLAGS $LCMS_CFLAGS
VIPS_CFLAGS=`for i in $VIPS_CFLAGS $GTHREAD_CFLAGS $REQUIRED_CFLAGS $PANGOFT2_CFLAGS $FFTW_CFLAGS $MAGICK_CFLAGS $PNG_CFLAGS $EXIF_CFLAGS $MATIO_CFLAGS $CFITSIO_CFLAGS $LIBWEBP_CFLAGS $OPENEXR_CFLAGS $OPENSLIDE_CFLAGS $ORC_CFLAGS $TIFF_CFLAGS $LCMS_CFLAGS
do
echo $i
done | sort -ru`
VIPS_CFLAGS=`echo $VIPS_CFLAGS`
VIPS_CFLAGS="$VIPS_DEBUG_FLAGS $VIPS_CFLAGS"
VIPS_INCLUDES="$PNG_INCLUDES $TIFF_INCLUDES $ZIP_INCLUDES $JPEG_INCLUDES"
VIPS_LIBS="$MAGICK_LIBS $PNG_LIBS $TIFF_LIBS $ZIP_LIBS $JPEG_LIBS $GTHREAD_LIBS $REQUIRED_LIBS $PANGOFT2_LIBS $FFTW_LIBS $ORC_LIBS $LCMS_LIBS $OPENEXR_LIBS $OPENSLIDE_LIBS $CFITSIO_LIBS $MATIO_LIBS $EXIF_LIBS -lm"
VIPS_LIBS="$MAGICK_LIBS $PNG_LIBS $TIFF_LIBS $ZIP_LIBS $JPEG_LIBS $GTHREAD_LIBS $REQUIRED_LIBS $PANGOFT2_LIBS $FFTW_LIBS $ORC_LIBS $LCMS_LIBS $OPENEXR_LIBS $OPENSLIDE_LIBS $CFITSIO_LIBS $LIBWEBP_LIBS $MATIO_LIBS $EXIF_LIBS -lm"
# we need this to generate paths in swig/python/setup.py.in
AC_SUBST(top_srcdir)

View File

@ -32,9 +32,9 @@
*/
/*
*/
#define DEBUG_VERBOSE
#define DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
@ -43,20 +43,116 @@
#ifdef HAVE_LIBWEBP
#include <stdlib.h>
#include <webp/decode.h>
#include <vips/vips.h>
#include "webp.h"
/* How many bytes do we need to read from the start of the file to be able to
* validate the header?
*
* This doesn't seem to be documented anywhere :-( guess a value.
*/
#define MINIMAL_HEADER (100)
/* What we track during a read.
*/
typedef struct {
/* File source.
*/
char *filename;
/* Memory source.
*/
void *buf;
size_t len;
/* Decoder config.
*/
WebPDecoderConfig config;
/* Incremental decoder state.
*/
WebPIDecoder *idec;
} Read;
int
vips__iswebp( const char *filename )
{
unsigned char buf[2];
unsigned char header[MINIMAL_HEADER];
if( vips__get_bytes( filename, buf, 2 ) )
if( (int) buf[0] == 0xff && (int) buf[1] == 0xd8 )
return( 1 );
if( vips__get_bytes( filename, header, MINIMAL_HEADER ) &&
WebPGetInfo( header, MINIMAL_HEADER, NULL, NULL ) )
return( 1 );
return( 0 );
}
static int
read_free( Read *read )
{
VIPS_FREE( read->filename );
VIPS_FREEF( WebPIDelete, read->idec );
WebPFreeDecBuffer( &read->config.output );
VIPS_FREE( read );
return( 0 );
}
static Read *
read_new( const char *filename, void *buf, size_t len )
{
Read *read;
unsigned char header[MINIMAL_HEADER];
if( !(read = VIPS_NEW( NULL, Read )) )
return( NULL );
read->filename = g_strdup( filename );
read->buf = buf;
read->len = len;
read->idec = NULL;
WebPInitDecoderConfig( &read->config );
if( filename ) {
if( vips__get_bytes( filename, header, MINIMAL_HEADER ) &&
WebPGetFeatures( header, MINIMAL_HEADER,
&read->config.input ) != VP8_STATUS_OK ) {
read_free( read );
return( NULL );
}
}
else {
if( WebPGetFeatures( read->buf, read->len,
&read->config.input ) != VP8_STATUS_OK ) {
read_free( read );
return( NULL );
}
}
if( read->config.input.has_alpha )
read->config.output.colorspace = MODE_RGBA;
else
read->config.output.colorspace = MODE_RGB;
read->config.options.use_threads = TRUE;
return( read );
}
static int
read_header( Read *read, VipsImage *out )
{
vips_image_init_fields( out,
read->config.input.width, read->config.input.height,
read->config.input.has_alpha ? 4 : 3,
VIPS_FORMAT_UCHAR, VIPS_CODING_NONE,
VIPS_INTERPRETATION_sRGB,
1.0, 1.0 );
vips_demand_hint( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
return( 0 );
}
@ -64,7 +160,65 @@ vips__iswebp( const char *filename )
int
vips__webp_read_file_header( const char *filename, VipsImage *out )
{
printf( "vips__webp_read_file_header\n" );
Read *read;
if( !(read = read_new( filename, NULL, 0 )) ) {
vips_error( "webp2vips",
_( "unable to open \"%s\"" ), filename );
return( -1 );
}
if( read_header( read, out ) )
return( -1 );
read_free( read );
return( 0 );
}
typedef uint8_t *(*webp_reader)( 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 );
char *data;
unsigned int len;
webp_reader reader;
/* libwebp makes streaming very hard. We have to read to a full memory
* buffer, then copy to out.
*/
t[0] = vips_image_new_buffer();
if( read_header( read, t[0] ) )
return( -1 );
if( vips_image_write_prepare( t[0] ) )
return( -1 );
if( !(data = vips__file_read_name( read->filename, NULL, &len )) )
return( -1 );
if( t[0]->Bands == 3 )
reader = WebPDecodeRGBInto;
else
reader = WebPDecodeRGBAInto;
if( !reader( (uint8_t *) data, len,
VIPS_IMAGE_ADDR( t[0], 0, 0 ),
VIPS_IMAGE_SIZEOF_IMAGE( t[0] ),
VIPS_IMAGE_SIZEOF_LINE( t[0] ) ) ) {
g_free( data );
vips_error( "webp2vips", "%s", _( "unable to read pixels" ) );
return( -1 );
}
g_free( data );
if( vips_image_write( t[0], out ) )
return( -1 );
return( 0 );
}
@ -72,7 +226,18 @@ vips__webp_read_file_header( const char *filename, VipsImage *out )
int
vips__webp_read_file( const char *filename, VipsImage *out )
{
printf( "vips__webp_read_file\n" );
Read *read;
if( !(read = read_new( filename, NULL, 0 )) ) {
vips_error( "webp2vips",
_( "unable to open \"%s\"" ), filename );
return( -1 );
}
if( read_image( read, out ) )
return( -1 );
read_free( read );
return( 0 );
}
@ -80,7 +245,18 @@ vips__webp_read_file( const char *filename, VipsImage *out )
int
vips__webp_read_buffer_header( void *buf, size_t len, VipsImage *out )
{
printf( "vips__webp_read_buffer_header\n" );
Read *read;
if( !(read = read_new( NULL, buf, len )) ) {
vips_error( "webp2vips",
"%s", _( "unable to open buffer" ) );
return( -1 );
}
if( read_header( read, out ) )
return( -1 );
read_free( read );
return( 0 );
}
@ -88,11 +264,18 @@ vips__webp_read_buffer_header( void *buf, size_t len, VipsImage *out )
int
vips__webp_read_buffer( void *buf, size_t len, VipsImage *out )
{
printf( "vips__webp_read_buffer\n" );
Read *read;
if( !(read = read_new( NULL, buf, len )) ) {
vips_error( "webp2vips",
"%s", _( "unable to open buffer" ) );
return( -1 );
}
if( read_image( read, out ) )
return( -1 );
return( 0 );
}
#endif /*HAVE_LIBWEBP*/

View File

@ -37,9 +37,9 @@
*/
/*
*/
#define VIPS_DEBUG
#define DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>