add webpload stream
webp uses the new VipsStreamInput mmap interface
This commit is contained in:
parent
5a788b89cf
commit
98410042ac
@ -85,7 +85,6 @@ png2vips( const char *name, IMAGE *out, gboolean header_only )
|
||||
#ifdef HAVE_PNG
|
||||
{
|
||||
VipsStreamInput *input;
|
||||
|
||||
int result;
|
||||
|
||||
if( !(input = vips_stream_input_new_from_filename( filename )) )
|
||||
|
@ -51,14 +51,21 @@ webp2vips( const char *name, IMAGE *out, gboolean header_only )
|
||||
im_filename_split( name, filename, mode );
|
||||
|
||||
#ifdef HAVE_LIBWEBP
|
||||
if( header_only ) {
|
||||
if( vips__webp_read_file_header( filename, out, 0, 1, 1 ) )
|
||||
return( -1 );
|
||||
}
|
||||
else {
|
||||
if( vips__webp_read_file( filename, out, 0, 1, 1 ) )
|
||||
return( -1 );
|
||||
}
|
||||
{
|
||||
VipsStreamInput *input;
|
||||
int result;
|
||||
|
||||
if( !(input = vips_stream_input_new_from_filename( filename )) )
|
||||
return( -1 );
|
||||
if( header_only )
|
||||
result = vips__webp_read_header_stream( input, out, 0, 1, 1 );
|
||||
else
|
||||
result = vips__webp_read_stream( input, out, 0, 1, 1 );
|
||||
VIPS_UNREF( input );
|
||||
|
||||
if( result )
|
||||
return( result );
|
||||
}
|
||||
#else
|
||||
vips_error( "im_webp2vips",
|
||||
"%s", _( "no webp support in your libvips" ) );
|
||||
@ -69,6 +76,25 @@ webp2vips( const char *name, IMAGE *out, gboolean header_only )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static gboolean
|
||||
vips__iswebp( const char *filename )
|
||||
{
|
||||
gboolean result;
|
||||
|
||||
#ifdef HAVE_LIBWEBP
|
||||
VipsStreamInput *input;
|
||||
|
||||
if( !(input = vips_stream_input_new_from_filename( filename )) )
|
||||
return( FALSE );
|
||||
result = vips__png_ispng_stream( input );
|
||||
VIPS_UNREF( input );
|
||||
#else /*!HAVE_LIBWEBP*/
|
||||
result = -1;
|
||||
#endif /*HAVE_LIBWEBP*/
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
int
|
||||
im_webp2vips( const char *name, IMAGE *out )
|
||||
{
|
||||
|
@ -2022,6 +2022,7 @@ vips_foreign_operation_init( void )
|
||||
extern GType vips_foreign_save_magick_buffer_get_type( void );
|
||||
extern GType vips_foreign_save_dz_file_get_type( void );
|
||||
extern GType vips_foreign_save_dz_buffer_get_type( void );
|
||||
extern GType vips_foreign_load_webp_stream_get_type( void );
|
||||
extern GType vips_foreign_load_webp_file_get_type( void );
|
||||
extern GType vips_foreign_load_webp_buffer_get_type( void );
|
||||
extern GType vips_foreign_save_webp_file_get_type( void );
|
||||
@ -2122,6 +2123,7 @@ vips_foreign_operation_init( void )
|
||||
#endif /*HAVE_JPEG*/
|
||||
|
||||
#ifdef HAVE_LIBWEBP
|
||||
vips_foreign_load_webp_stream_get_type();
|
||||
vips_foreign_load_webp_file_get_type();
|
||||
vips_foreign_load_webp_buffer_get_type();
|
||||
vips_foreign_save_webp_file_get_type();
|
||||
|
@ -207,17 +207,11 @@ extern const VipsWebPNames vips__webp_names[];
|
||||
extern const int vips__n_webp_names;
|
||||
extern const char *vips__webp_suffs[];
|
||||
|
||||
int vips__iswebp_buffer( const void *buf, size_t len );
|
||||
int vips__iswebp( const char *filename );
|
||||
int vips__iswebp_stream( VipsStreamInput *input );
|
||||
|
||||
int vips__webp_read_file_header( const char *name, VipsImage *out,
|
||||
int vips__webp_read_header_stream( VipsStreamInput *input, VipsImage *out,
|
||||
int page, int n, double scale );
|
||||
int vips__webp_read_file( const char *name, VipsImage *out,
|
||||
int page, int n, double scale );
|
||||
|
||||
int vips__webp_read_buffer_header( const void *buf, size_t len, VipsImage *out,
|
||||
int page, int n, double scale );
|
||||
int vips__webp_read_buffer( const void *buf, size_t len, VipsImage *out,
|
||||
int vips__webp_read_stream( VipsStreamInput *input, VipsImage *out,
|
||||
int page, int n, double scale );
|
||||
|
||||
int vips__webp_write_file( VipsImage *out, const char *filename,
|
||||
|
@ -24,6 +24,8 @@
|
||||
* - disable alpha output if all frame fill the canvas and are solid
|
||||
* 6/7/19 [deftomat]
|
||||
* - support array of delays
|
||||
* 14/10/19
|
||||
* - revise for stream IO
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -79,15 +81,11 @@
|
||||
/* What we track during a read.
|
||||
*/
|
||||
typedef struct {
|
||||
/* File source.
|
||||
*/
|
||||
char *filename;
|
||||
VipsStreamInput *input;
|
||||
|
||||
/* Memory source. We use gint64 rather than size_t since we use
|
||||
* vips_file_length() and vips__mmap() for file sources.
|
||||
/* The data we load, as a webp object.
|
||||
*/
|
||||
const void *data;
|
||||
gint64 length;
|
||||
WebPData data;
|
||||
|
||||
/* Load this page (frame number).
|
||||
*/
|
||||
@ -128,10 +126,6 @@ typedef struct {
|
||||
*/
|
||||
int *delays;
|
||||
|
||||
/* If we are opening a file object, the fd.
|
||||
*/
|
||||
int fd;
|
||||
|
||||
/* Parse with this.
|
||||
*/
|
||||
WebPDemuxer *demux;
|
||||
@ -317,57 +311,24 @@ vips_image_paint_image( VipsImage *frame,
|
||||
}
|
||||
|
||||
int
|
||||
vips__iswebp_buffer( const void *buf, size_t len )
|
||||
vips__iswebp_stream( VipsStreamInput *input )
|
||||
{
|
||||
const unsigned char *p;
|
||||
|
||||
/* WebP is "RIFF xxxx WEBP" at the start, so we need 12 bytes.
|
||||
*/
|
||||
if( len >= 12 &&
|
||||
vips_isprefix( "RIFF", (char *) buf ) &&
|
||||
vips_isprefix( "WEBP", (char *) buf + 8 ) )
|
||||
if( (p = vips_stream_input_sniff( input, 12 )) &&
|
||||
vips_isprefix( "RIFF", (char *) p ) &&
|
||||
vips_isprefix( "WEBP", (char *) p + 8 ) )
|
||||
return( 1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
vips__iswebp( const char *filename )
|
||||
{
|
||||
/* Magic number, see above.
|
||||
*/
|
||||
unsigned char header[12];
|
||||
|
||||
if( vips__get_bytes( filename, header, 12 ) == 12 &&
|
||||
vips__iswebp_buffer( header, 12 ) )
|
||||
return( 1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
read_minimise( Read *read )
|
||||
{
|
||||
WebPDemuxReleaseIterator( &read->iter );
|
||||
VIPS_UNREF( read->frame );
|
||||
VIPS_FREEF( WebPDemuxDelete, read->demux );
|
||||
WebPFreeDecBuffer( &read->config.output );
|
||||
|
||||
if( read->fd > 0 &&
|
||||
read->data &&
|
||||
read->length > 0 ) {
|
||||
vips__munmap( read->data, read->length );
|
||||
read->data = NULL;
|
||||
read->length = 0;
|
||||
}
|
||||
|
||||
VIPS_FREEF( vips_tracked_close, read->fd );
|
||||
}
|
||||
|
||||
static int
|
||||
read_free( Read *read )
|
||||
{
|
||||
read_minimise( read );
|
||||
|
||||
VIPS_FREE( read->filename );
|
||||
VIPS_UNREF( read->input );
|
||||
VIPS_FREE( read->delays );
|
||||
VIPS_FREE( read );
|
||||
|
||||
@ -375,46 +336,34 @@ read_free( Read *read )
|
||||
}
|
||||
|
||||
static Read *
|
||||
read_new( const char *filename, const void *data, size_t length,
|
||||
int page, int n, double scale )
|
||||
read_new( VipsStreamInput *input, int page, int n, double scale )
|
||||
{
|
||||
Read *read;
|
||||
|
||||
if( !(read = VIPS_NEW( NULL, Read )) )
|
||||
return( NULL );
|
||||
|
||||
read->filename = g_strdup( filename );
|
||||
read->data = data;
|
||||
read->length = length;
|
||||
read->input = input;
|
||||
g_object_ref( input );
|
||||
read->page = page;
|
||||
read->n = n;
|
||||
read->scale = scale;
|
||||
read->delays = NULL;
|
||||
read->fd = 0;
|
||||
read->demux = NULL;
|
||||
read->frame = NULL;
|
||||
read->dispose_method = WEBP_MUX_DISPOSE_NONE;
|
||||
read->frame_no = 0;
|
||||
|
||||
if( read->filename ) {
|
||||
/* libwebp makes streaming from a file source very hard. We
|
||||
* have to read to a full memory buffer, then copy to out.
|
||||
*
|
||||
* mmap the input file, it's slightly quicker.
|
||||
*/
|
||||
if( (read->fd = vips__open_image_read( read->filename )) < 0 ||
|
||||
(read->length = vips_file_length( read->fd )) < 0 ||
|
||||
!(read->data = vips__mmap( read->fd,
|
||||
FALSE, read->length, 0 )) ) {
|
||||
read_free( read );
|
||||
return( NULL );
|
||||
}
|
||||
}
|
||||
|
||||
WebPInitDecoderConfig( &read->config );
|
||||
read->config.options.use_threads = 1;
|
||||
read->config.output.is_external_memory = 1;
|
||||
|
||||
if( !(read->data.bytes =
|
||||
vips_stream_input_map( input, &read->data.size )) ) {
|
||||
read_free( read );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
return( read );
|
||||
}
|
||||
|
||||
@ -430,13 +379,10 @@ const int vips__n_webp_names = VIPS_NUMBER( vips__webp_names );
|
||||
static int
|
||||
read_header( Read *read, VipsImage *out )
|
||||
{
|
||||
WebPData data;
|
||||
int flags;
|
||||
int i;
|
||||
|
||||
data.bytes = read->data;
|
||||
data.size = read->length;
|
||||
if( !(read->demux = WebPDemux( &data )) ) {
|
||||
if( !(read->demux = WebPDemux( &read->data )) ) {
|
||||
vips_error( "webp", "%s", _( "unable to parse image" ) );
|
||||
return( -1 );
|
||||
}
|
||||
@ -599,28 +545,6 @@ read_header( Read *read, VipsImage *out )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
vips__webp_read_file_header( const char *filename, VipsImage *out,
|
||||
int page, int n, double scale )
|
||||
{
|
||||
Read *read;
|
||||
|
||||
if( !(read = read_new( filename, NULL, 0, page, n, scale )) ) {
|
||||
vips_error( "webp2vips",
|
||||
_( "unable to open \"%s\"" ), filename );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( read_header( read, out ) ) {
|
||||
read_free( read );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
read_free( read );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Read a single frame -- a width * height block of pixels. This will get
|
||||
* blended into the accumulator at some offset.
|
||||
*/
|
||||
@ -803,12 +727,6 @@ read_webp_generate( VipsRegion *or,
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
read_minimise_cb( VipsObject *object, Read *read )
|
||||
{
|
||||
read_minimise( read );
|
||||
}
|
||||
|
||||
static int
|
||||
read_image( Read *read, VipsImage *out )
|
||||
{
|
||||
@ -819,9 +737,6 @@ read_image( Read *read, VipsImage *out )
|
||||
if( read_header( read, t[0] ) )
|
||||
return( -1 );
|
||||
|
||||
g_signal_connect( t[0], "minimise",
|
||||
G_CALLBACK( read_minimise_cb ), read );
|
||||
|
||||
if( vips_image_generate( t[0],
|
||||
NULL, read_webp_generate, NULL, read, NULL ) ||
|
||||
vips_sequential( t[0], &t[1], NULL ) ||
|
||||
@ -832,38 +747,13 @@ read_image( Read *read, VipsImage *out )
|
||||
}
|
||||
|
||||
int
|
||||
vips__webp_read_file( const char *filename, VipsImage *out,
|
||||
vips__webp_read_header_stream( VipsStreamInput *input, VipsImage *out,
|
||||
int page, int n, double scale )
|
||||
{
|
||||
Read *read;
|
||||
|
||||
if( !(read = read_new( filename, NULL, 0, page, n, scale )) ) {
|
||||
vips_error( "webp2vips",
|
||||
_( "unable to open \"%s\"" ), filename );
|
||||
if( !(read = read_new( input, page, n, scale )) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( read_image( read, out ) ) {
|
||||
read_free( read );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
read_free( read );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
vips__webp_read_buffer_header( const void *buf, size_t len, VipsImage *out,
|
||||
int page, int n, double scale )
|
||||
{
|
||||
Read *read;
|
||||
|
||||
if( !(read = read_new( NULL, buf, len, page, n, scale )) ) {
|
||||
vips_error( "webp2vips",
|
||||
"%s", _( "unable to open buffer" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( read_header( read, out ) ) {
|
||||
read_free( read );
|
||||
@ -876,16 +766,13 @@ 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_stream( VipsStreamInput *input, VipsImage *out,
|
||||
int page, int n, double scale )
|
||||
{
|
||||
Read *read;
|
||||
|
||||
if( !(read = read_new( NULL, buf, len, page, n, scale )) ) {
|
||||
vips_error( "webp2vips",
|
||||
"%s", _( "unable to open buffer" ) );
|
||||
if( !(read = read_new( input, page, n, scale )) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( read_image( read, out ) ) {
|
||||
read_free( read );
|
||||
|
@ -153,6 +153,81 @@ vips_foreign_load_webp_init( VipsForeignLoadWebp *webp )
|
||||
webp->scale = 1.0;
|
||||
}
|
||||
|
||||
typedef struct _VipsForeignLoadWebpStream {
|
||||
VipsForeignLoadWebp parent_object;
|
||||
|
||||
VipsStreamInput *input;
|
||||
|
||||
} VipsForeignLoadWebpStream;
|
||||
|
||||
typedef VipsForeignLoadWebpClass VipsForeignLoadWebpStreamClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsForeignLoadWebpStream, vips_foreign_load_webp_stream,
|
||||
vips_foreign_load_webp_get_type() );
|
||||
|
||||
static int
|
||||
vips_foreign_load_webp_stream_header( VipsForeignLoad *load )
|
||||
{
|
||||
VipsForeignLoadWebp *webp = (VipsForeignLoadWebp *) load;
|
||||
VipsForeignLoadWebpStream *stream = (VipsForeignLoadWebpStream *) load;
|
||||
|
||||
if( vips__webp_read_header_stream( stream->input, load->out,
|
||||
webp->page, webp->n, webp->scale ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_foreign_load_webp_stream_load( VipsForeignLoad *load )
|
||||
{
|
||||
VipsForeignLoadWebp *webp = (VipsForeignLoadWebp *) load;
|
||||
VipsForeignLoadWebpStream *stream = (VipsForeignLoadWebpStream *) load;
|
||||
|
||||
if( vips__webp_read_stream( stream->input, load->real,
|
||||
webp->page, webp->n, webp->scale ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_load_webp_stream_class_init(
|
||||
VipsForeignLoadWebpStreamClass *class )
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||
VipsObjectClass *object_class = (VipsObjectClass *) class;
|
||||
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
|
||||
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
|
||||
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
object_class->nickname = "webpload_stream";
|
||||
object_class->description = _( "load webp from stream" );
|
||||
|
||||
/* is_a() is not that quick ... lower the priority.
|
||||
*/
|
||||
foreign_class->priority = -50;
|
||||
|
||||
load_class->is_a_stream = vips__iswebp_stream;
|
||||
load_class->header = vips_foreign_load_webp_stream_header;
|
||||
load_class->load = vips_foreign_load_webp_stream_load;
|
||||
|
||||
VIPS_ARG_OBJECT( class, "input", 1,
|
||||
_( "Input" ),
|
||||
_( "Stream to load from" ),
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
G_STRUCT_OFFSET( VipsForeignLoadWebpStream, input ),
|
||||
VIPS_TYPE_STREAM_INPUT );
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_load_webp_stream_init( VipsForeignLoadWebpStream *buffer )
|
||||
{
|
||||
}
|
||||
|
||||
typedef struct _VipsForeignLoadWebpFile {
|
||||
VipsForeignLoadWebp parent_object;
|
||||
|
||||
@ -176,7 +251,15 @@ vips_foreign_load_webp_file_get_flags_filename( const char *filename )
|
||||
static gboolean
|
||||
vips_foreign_load_webp_file_is_a( const char *filename )
|
||||
{
|
||||
return( vips__iswebp( filename ) );
|
||||
VipsStreamInput *input;
|
||||
gboolean result;
|
||||
|
||||
if( !(input = vips_stream_input_new_from_filename( filename )) )
|
||||
return( FALSE );
|
||||
result = vips__iswebp_stream( input );
|
||||
VIPS_UNREF( input );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
static int
|
||||
@ -185,6 +268,8 @@ vips_foreign_load_webp_file_header( VipsForeignLoad *load )
|
||||
VipsForeignLoadWebp *webp = (VipsForeignLoadWebp *) load;
|
||||
VipsForeignLoadWebpFile *file = (VipsForeignLoadWebpFile *) load;
|
||||
|
||||
VipsStreamInput *input;
|
||||
|
||||
/* BC for the old API.
|
||||
*/
|
||||
if( !vips_object_argument_isset( VIPS_OBJECT( load ), "scale" ) &&
|
||||
@ -192,9 +277,14 @@ vips_foreign_load_webp_file_header( VipsForeignLoad *load )
|
||||
webp->shrink != 0 )
|
||||
webp->scale = 1.0 / webp->shrink;
|
||||
|
||||
if( vips__webp_read_file_header( file->filename, load->out,
|
||||
webp->page, webp->n, webp->scale ) )
|
||||
if( !(input = vips_stream_input_new_from_filename( file->filename )) )
|
||||
return( -1 );
|
||||
if( vips__webp_read_header_stream( input, load->out,
|
||||
webp->page, webp->n, webp->scale ) ) {
|
||||
VIPS_UNREF( input );
|
||||
return( -1 );
|
||||
}
|
||||
VIPS_UNREF( input );
|
||||
|
||||
VIPS_SETSTR( load->out->filename, file->filename );
|
||||
|
||||
@ -207,9 +297,16 @@ 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,
|
||||
webp->page, webp->n, webp->scale ) )
|
||||
VipsStreamInput *input;
|
||||
|
||||
if( !(input = vips_stream_input_new_from_filename( file->filename )) )
|
||||
return( -1 );
|
||||
if( vips__webp_read_stream( input, load->real,
|
||||
webp->page, webp->n, webp->scale ) ) {
|
||||
VIPS_UNREF( input );
|
||||
return( -1 );
|
||||
}
|
||||
VIPS_UNREF( input );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
@ -265,16 +362,37 @@ typedef VipsForeignLoadWebpClass VipsForeignLoadWebpBufferClass;
|
||||
G_DEFINE_TYPE( VipsForeignLoadWebpBuffer, vips_foreign_load_webp_buffer,
|
||||
vips_foreign_load_webp_get_type() );
|
||||
|
||||
static gboolean
|
||||
vips_foreign_load_webp_buffer_is_a_buffer( const void *buf, size_t len )
|
||||
{
|
||||
VipsStreamInput *input;
|
||||
gboolean result;
|
||||
|
||||
if( !(input = vips_stream_input_new_from_memory( buf, len )) )
|
||||
return( FALSE );
|
||||
result = vips__iswebp_stream( input );
|
||||
VIPS_UNREF( input );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
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,
|
||||
webp->page, webp->n, webp->scale ) )
|
||||
VipsStreamInput *input;
|
||||
|
||||
if( !(input = vips_stream_input_new_from_memory( buffer->buf->data,
|
||||
buffer->buf->length )) )
|
||||
return( FALSE );
|
||||
if( vips__webp_read_header_stream( input, load->out,
|
||||
webp->page, webp->n, webp->scale ) ) {
|
||||
VIPS_UNREF( input );
|
||||
return( -1 );
|
||||
}
|
||||
VIPS_UNREF( input );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
@ -285,10 +403,17 @@ 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,
|
||||
webp->page, webp->n, webp->scale ) )
|
||||
VipsStreamInput *input;
|
||||
|
||||
if( !(input = vips_stream_input_new_from_memory( buffer->buf->data,
|
||||
buffer->buf->length )) )
|
||||
return( FALSE );
|
||||
if( vips__webp_read_stream( input, load->real,
|
||||
webp->page, webp->n, webp->scale ) ) {
|
||||
VIPS_UNREF( input );
|
||||
return( -1 );
|
||||
}
|
||||
VIPS_UNREF( input );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
@ -312,7 +437,7 @@ vips_foreign_load_webp_buffer_class_init(
|
||||
*/
|
||||
foreign_class->priority = -50;
|
||||
|
||||
load_class->is_a_buffer = vips__iswebp_buffer;
|
||||
load_class->is_a_buffer = vips_foreign_load_webp_buffer_is_a_buffer;
|
||||
load_class->header = vips_foreign_load_webp_buffer_header;
|
||||
load_class->load = vips_foreign_load_webp_buffer_load;
|
||||
|
||||
@ -416,3 +541,34 @@ vips_webpload_buffer( void *buf, size_t len, VipsImage **out, ... )
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_webpload_stream:
|
||||
* @input: stream to load from
|
||||
* @out: (out): image to write
|
||||
* @...: %NULL-terminated list of optional named arguments
|
||||
*
|
||||
* Optional arguments:
|
||||
*
|
||||
* * @page: %gint, page (frame) to read
|
||||
* * @n: %gint, load this many pages
|
||||
* * @scale: %gdouble, scale by this much on load
|
||||
*
|
||||
* Exactly as vips_webpload(), but read from a stream.
|
||||
*
|
||||
* See also: vips_webpload()
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
int
|
||||
vips_webpload_stream( VipsStreamInput *input, VipsImage **out, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_start( ap, out );
|
||||
result = vips_call_split( "webpload_stream", ap, input, out );
|
||||
va_end( ap );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
@ -399,6 +399,8 @@ typedef enum {
|
||||
VIPS_FOREIGN_WEBP_PRESET_LAST
|
||||
} VipsForeignWebpPreset;
|
||||
|
||||
int vips_webpload_stream( VipsStreamInput *input, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_webpload( const char *filename, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_webpload_buffer( void *buf, size_t len, VipsImage **out, ... )
|
||||
|
@ -191,6 +191,7 @@ VipsStreamInput *vips_stream_input_new_from_options( const char *options );
|
||||
|
||||
ssize_t vips_stream_input_read( VipsStreamInput *input,
|
||||
unsigned char *data, size_t length );
|
||||
const void *vips_stream_input_map( VipsStreamInput *input, size_t *length );
|
||||
int vips_stream_input_rewind( VipsStreamInput *input );
|
||||
void vips_stream_input_minimise( VipsStreamInput *input );
|
||||
void vips_stream_input_decode( VipsStreamInput *input );
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* A byte source/sink .. it can be a pipe, file descriptor, memory area,
|
||||
* socket, or perhaps a node.js stream.
|
||||
* socket, node.js stream, etc.
|
||||
*
|
||||
* J.Cupitt, 19/6/14
|
||||
*/
|
||||
@ -34,11 +34,10 @@
|
||||
/* TODO
|
||||
*
|
||||
* - filename encoding
|
||||
* - add mmapable descriptors
|
||||
* - add seekable descriptors
|
||||
* - test for mmapable
|
||||
* - can we really change all behaviour in the subclass? will we need map and
|
||||
* seek as well as read and rewind?
|
||||
* - add seekable input sources
|
||||
* - need to be able to set seekable and mapable via constructor
|
||||
* - test we can really change all behaviour in the subclass ... add callbacks
|
||||
* as well to make it simpler for language bindings
|
||||
*/
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user