add thumbnail_stream
this works: $ cat k2.jpg | vips thumbnail_stream [descriptor=0] x.jpg 200 $ vipsheader x.jpg temp-0: 141x200 uchar, 3 bands, srgb, jpegload
This commit is contained in:
parent
4d3f66fe33
commit
5f6911d516
|
@ -79,6 +79,9 @@ int vips_thumbnail_buffer( void *buf, size_t len, VipsImage **out,
|
||||||
__attribute__((sentinel));
|
__attribute__((sentinel));
|
||||||
int vips_thumbnail_image( VipsImage *in, VipsImage **out, int width, ... )
|
int vips_thumbnail_image( VipsImage *in, VipsImage **out, int width, ... )
|
||||||
__attribute__((sentinel));
|
__attribute__((sentinel));
|
||||||
|
int vips_thumbnail_stream( VipsStreamInput *input, VipsImage **out,
|
||||||
|
int width, ... )
|
||||||
|
__attribute__((sentinel));
|
||||||
|
|
||||||
int vips_similarity( VipsImage *in, VipsImage **out, ... )
|
int vips_similarity( VipsImage *in, VipsImage **out, ... )
|
||||||
__attribute__((sentinel));
|
__attribute__((sentinel));
|
||||||
|
|
|
@ -171,6 +171,7 @@ VipsStreamInput *vips_stream_input_new_from_filename( const char *filename );
|
||||||
VipsStreamInput *vips_stream_input_new_from_blob( VipsBlob *blob );
|
VipsStreamInput *vips_stream_input_new_from_blob( VipsBlob *blob );
|
||||||
VipsStreamInput *vips_stream_input_new_from_memory( const void *data,
|
VipsStreamInput *vips_stream_input_new_from_memory( const void *data,
|
||||||
size_t size );
|
size_t size );
|
||||||
|
VipsStreamInput *vips_stream_input_new_from_options( const char *options );
|
||||||
|
|
||||||
ssize_t vips_stream_input_read( VipsStreamInput *input,
|
ssize_t vips_stream_input_read( VipsStreamInput *input,
|
||||||
unsigned char *data, size_t length );
|
unsigned char *data, size_t length );
|
||||||
|
|
|
@ -1889,18 +1889,11 @@ vips_object_set_argument_from_string( VipsObject *object,
|
||||||
char filename[VIPS_PATH_MAX];
|
char filename[VIPS_PATH_MAX];
|
||||||
char option_string[VIPS_PATH_MAX];
|
char option_string[VIPS_PATH_MAX];
|
||||||
|
|
||||||
if( !value ) {
|
|
||||||
vips_object_no_value( object, name );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
flags = 0;
|
flags = 0;
|
||||||
if( VIPS_IS_OPERATION( object ) )
|
if( VIPS_IS_OPERATION( object ) )
|
||||||
flags = vips_operation_get_flags(
|
flags = vips_operation_get_flags(
|
||||||
VIPS_OPERATION( object ) );
|
VIPS_OPERATION( object ) );
|
||||||
|
|
||||||
/* Read the filename.
|
|
||||||
*/
|
|
||||||
if( flags &
|
if( flags &
|
||||||
(VIPS_OPERATION_SEQUENTIAL_UNBUFFERED |
|
(VIPS_OPERATION_SEQUENTIAL_UNBUFFERED |
|
||||||
VIPS_OPERATION_SEQUENTIAL) )
|
VIPS_OPERATION_SEQUENTIAL) )
|
||||||
|
@ -1908,6 +1901,10 @@ vips_object_set_argument_from_string( VipsObject *object,
|
||||||
else
|
else
|
||||||
access = VIPS_ACCESS_RANDOM;
|
access = VIPS_ACCESS_RANDOM;
|
||||||
|
|
||||||
|
if( !value ) {
|
||||||
|
vips_object_no_value( object, name );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
vips__filename_split8( value, filename, option_string );
|
vips__filename_split8( value, filename, option_string );
|
||||||
|
|
||||||
if( strcmp( "stdin", filename ) == 0 ) {
|
if( strcmp( "stdin", filename ) == 0 ) {
|
||||||
|
@ -1940,6 +1937,25 @@ vips_object_set_argument_from_string( VipsObject *object,
|
||||||
*/
|
*/
|
||||||
g_object_unref( out );
|
g_object_unref( out );
|
||||||
}
|
}
|
||||||
|
else if( g_type_is_a( otype, VIPS_TYPE_STREAM_INPUT ) ) {
|
||||||
|
VipsStreamInput *input;
|
||||||
|
|
||||||
|
if( !value ) {
|
||||||
|
vips_object_no_value( object, name );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !(input = vips_stream_input_new_from_options( value )) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
g_value_init( &gvalue, VIPS_TYPE_STREAM_INPUT );
|
||||||
|
g_value_set_object( &gvalue, input );
|
||||||
|
|
||||||
|
/* Setting gvalue will have upped @out's count again,
|
||||||
|
* go back to 1 so that gvalue has the only ref.
|
||||||
|
*/
|
||||||
|
g_object_unref( input );
|
||||||
|
}
|
||||||
else if( g_type_is_a( otype, VIPS_TYPE_ARRAY_IMAGE ) ) {
|
else if( g_type_is_a( otype, VIPS_TYPE_ARRAY_IMAGE ) ) {
|
||||||
/* We have to have a special case for this, we can't just rely
|
/* We have to have a special case for this, we can't just rely
|
||||||
* on transform_g_string_array_image(), since we need to be
|
* on transform_g_string_array_image(), since we need to be
|
||||||
|
|
|
@ -1245,7 +1245,8 @@ typedef struct _VipsCall {
|
||||||
static const char *
|
static const char *
|
||||||
vips_call_get_arg( VipsCall *call, int i )
|
vips_call_get_arg( VipsCall *call, int i )
|
||||||
{
|
{
|
||||||
if( i < 0 || i >= call->argc ) {
|
if( i < 0 ||
|
||||||
|
i >= call->argc ) {
|
||||||
vips_error( VIPS_OBJECT_GET_CLASS( call->operation )->nickname,
|
vips_error( VIPS_OBJECT_GET_CLASS( call->operation )->nickname,
|
||||||
"%s", _( "too few arguments" ) );
|
"%s", _( "too few arguments" ) );
|
||||||
return( NULL );
|
return( NULL );
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
/* TODO
|
/* TODO
|
||||||
*
|
*
|
||||||
|
* - minimise support, and reenable jpg test_descriptors
|
||||||
* - filename encoding
|
* - filename encoding
|
||||||
* - memory output
|
* - memory output
|
||||||
* - add mmapable descriptors
|
* - add mmapable descriptors
|
||||||
|
@ -322,7 +323,7 @@ vips_stream_input_class_init( VipsStreamInputClass *class )
|
||||||
gobject_class->set_property = vips_object_set_property;
|
gobject_class->set_property = vips_object_set_property;
|
||||||
gobject_class->get_property = vips_object_get_property;
|
gobject_class->get_property = vips_object_get_property;
|
||||||
|
|
||||||
object_class->nickname = "input";
|
object_class->nickname = "stream_input";
|
||||||
object_class->description = _( "input stream" );
|
object_class->description = _( "input stream" );
|
||||||
|
|
||||||
object_class->build = vips_stream_input_build;
|
object_class->build = vips_stream_input_build;
|
||||||
|
@ -416,67 +417,84 @@ vips_stream_input_new_from_filename( const char *filename )
|
||||||
*
|
*
|
||||||
* Create a stream attached to an area of memory.
|
* Create a stream attached to an area of memory.
|
||||||
*
|
*
|
||||||
* #VipsStream s start out empty, you need to call
|
|
||||||
* vips_stream_input_refill() to fill them with bytes.
|
|
||||||
*
|
|
||||||
* See also: vips_stream_input_refill().
|
|
||||||
*
|
|
||||||
* Returns: a new #VipsStream
|
* Returns: a new #VipsStream
|
||||||
*/
|
*/
|
||||||
VipsStreamInput *
|
VipsStreamInput *
|
||||||
vips_stream_input_new_from_blob( VipsBlob *blob )
|
vips_stream_input_new_from_blob( VipsBlob *blob )
|
||||||
{
|
{
|
||||||
VipsStreamInput *stream;
|
VipsStreamInput *input;
|
||||||
|
|
||||||
VIPS_DEBUG_MSG( "vips_stream_input_new_from_blob: %p\n", blob );
|
VIPS_DEBUG_MSG( "vips_stream_input_new_from_blob: %p\n", blob );
|
||||||
|
|
||||||
stream = VIPS_STREAM_INPUT(
|
input = VIPS_STREAM_INPUT(
|
||||||
g_object_new( VIPS_TYPE_STREAM_INPUT,
|
g_object_new( VIPS_TYPE_STREAM_INPUT,
|
||||||
"blob", blob,
|
"blob", blob,
|
||||||
NULL ) );
|
NULL ) );
|
||||||
|
|
||||||
if( vips_object_build( VIPS_OBJECT( stream ) ) ) {
|
if( vips_object_build( VIPS_OBJECT( input ) ) ) {
|
||||||
VIPS_UNREF( stream );
|
VIPS_UNREF( input );
|
||||||
return( NULL );
|
return( NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
return( stream );
|
return( input );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vips_stream_input_new_from_memory:
|
* vips_stream_input_new_from_memory:
|
||||||
* @buf: memory area to load
|
* @data: memory area to load
|
||||||
* @len: size of memory area
|
* @length: size of memory area
|
||||||
*
|
*
|
||||||
* Create a stream attached to an area of memory.
|
* Create a stream attached to an area of memory.
|
||||||
*
|
*
|
||||||
* You must not free @buf while the stream is active.
|
* You must not free @data while the stream is active.
|
||||||
*
|
|
||||||
* #VipsStream s start out empty, you need to call
|
|
||||||
* vips_stream_input_refill() to fill them with bytes.
|
|
||||||
*
|
|
||||||
* See also: vips_stream_input_refill().
|
|
||||||
*
|
*
|
||||||
* Returns: a new #VipsStream
|
* Returns: a new #VipsStream
|
||||||
*/
|
*/
|
||||||
VipsStreamInput *
|
VipsStreamInput *
|
||||||
vips_stream_input_new_from_memory( const void *data, size_t size )
|
vips_stream_input_new_from_memory( const void *data, size_t length )
|
||||||
{
|
{
|
||||||
VipsStreamInput *stream;
|
VipsStreamInput *input;
|
||||||
VipsBlob *blob;
|
VipsBlob *blob;
|
||||||
|
|
||||||
VIPS_DEBUG_MSG( "vips_stream_input_new_from_buffer: %p, size = %zd\n",
|
VIPS_DEBUG_MSG( "vips_stream_input_new_from_buffer: "
|
||||||
data, size );
|
"%p, length = %zd\n", data, length );
|
||||||
|
|
||||||
/* We don't take a copy of the data or free it.
|
/* We don't take a copy of the data or free it.
|
||||||
*/
|
*/
|
||||||
blob = vips_blob_new( NULL, data, size );
|
blob = vips_blob_new( NULL, data, length );
|
||||||
|
|
||||||
stream = vips_stream_input_new_from_blob( blob );
|
input = vips_stream_input_new_from_blob( blob );
|
||||||
|
|
||||||
vips_area_unref( VIPS_AREA( blob ) );
|
vips_area_unref( VIPS_AREA( blob ) );
|
||||||
|
|
||||||
return( stream );
|
return( input );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vips_stream_input_new_from_options:
|
||||||
|
* @options: option string
|
||||||
|
*
|
||||||
|
* Create a stream from an option string.
|
||||||
|
*
|
||||||
|
* Returns: a new #VipsStream
|
||||||
|
*/
|
||||||
|
VipsStreamInput *
|
||||||
|
vips_stream_input_new_from_options( const char *options )
|
||||||
|
{
|
||||||
|
VipsStreamInput *input;
|
||||||
|
|
||||||
|
VIPS_DEBUG_MSG( "vips_stream_input_new_from_options: %s\n", options );
|
||||||
|
|
||||||
|
input = VIPS_STREAM_INPUT(
|
||||||
|
g_object_new( VIPS_TYPE_STREAM_INPUT, NULL ) );
|
||||||
|
|
||||||
|
if( vips_object_set_from_string( VIPS_OBJECT( input ), options ) ||
|
||||||
|
vips_object_build( VIPS_OBJECT( input ) ) ) {
|
||||||
|
VIPS_UNREF( input );
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
return( input );
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
|
@ -696,7 +714,7 @@ vips_stream_output_class_init( VipsStreamOutputClass *class )
|
||||||
gobject_class->set_property = vips_object_set_property;
|
gobject_class->set_property = vips_object_set_property;
|
||||||
gobject_class->get_property = vips_object_get_property;
|
gobject_class->get_property = vips_object_get_property;
|
||||||
|
|
||||||
object_class->nickname = "output";
|
object_class->nickname = "stream_output";
|
||||||
object_class->description = _( "output stream" );
|
object_class->description = _( "output stream" );
|
||||||
|
|
||||||
object_class->build = vips_stream_output_build;
|
object_class->build = vips_stream_output_build;
|
||||||
|
@ -706,7 +724,7 @@ vips_stream_output_class_init( VipsStreamOutputClass *class )
|
||||||
/* SET_ALWAYS means that blob is set by C and the obj system is not
|
/* SET_ALWAYS means that blob is set by C and the obj system is not
|
||||||
* involved in creation or destruction. It can be read at any time.
|
* involved in creation or destruction. It can be read at any time.
|
||||||
*/
|
*/
|
||||||
VIPS_ARG_BOXED( class, "blob", 1,
|
VIPS_ARG_BOXED( class, "blob", 3,
|
||||||
_( "Blob" ),
|
_( "Blob" ),
|
||||||
_( "Blob to save to" ),
|
_( "Blob to save to" ),
|
||||||
VIPS_ARGUMENT_SET_ALWAYS,
|
VIPS_ARGUMENT_SET_ALWAYS,
|
||||||
|
|
|
@ -157,6 +157,7 @@ vips_resample_operation_init( void )
|
||||||
extern GType vips_thumbnail_file_get_type( void );
|
extern GType vips_thumbnail_file_get_type( void );
|
||||||
extern GType vips_thumbnail_buffer_get_type( void );
|
extern GType vips_thumbnail_buffer_get_type( void );
|
||||||
extern GType vips_thumbnail_image_get_type( void );
|
extern GType vips_thumbnail_image_get_type( void );
|
||||||
|
extern GType vips_thumbnail_stream_get_type( void );
|
||||||
extern GType vips_mapim_get_type( void );
|
extern GType vips_mapim_get_type( void );
|
||||||
extern GType vips_shrink_get_type( void );
|
extern GType vips_shrink_get_type( void );
|
||||||
extern GType vips_shrinkh_get_type( void );
|
extern GType vips_shrinkh_get_type( void );
|
||||||
|
@ -173,6 +174,7 @@ vips_resample_operation_init( void )
|
||||||
vips_thumbnail_file_get_type();
|
vips_thumbnail_file_get_type();
|
||||||
vips_thumbnail_buffer_get_type();
|
vips_thumbnail_buffer_get_type();
|
||||||
vips_thumbnail_image_get_type();
|
vips_thumbnail_image_get_type();
|
||||||
|
vips_thumbnail_stream_get_type();
|
||||||
vips_mapim_get_type();
|
vips_mapim_get_type();
|
||||||
vips_shrink_get_type();
|
vips_shrink_get_type();
|
||||||
vips_shrinkh_get_type();
|
vips_shrinkh_get_type();
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
* - prevent over-pre-shrink in thumbnail
|
* - prevent over-pre-shrink in thumbnail
|
||||||
* 30/9/19
|
* 30/9/19
|
||||||
* - smarter heif thumbnail selection
|
* - smarter heif thumbnail selection
|
||||||
|
* 12/10/19
|
||||||
|
* - add thumbnail_stream
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1249,6 +1251,175 @@ vips_thumbnail_buffer( void *buf, size_t len, VipsImage **out, int width, ... )
|
||||||
return( result );
|
return( result );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct _VipsThumbnailStream {
|
||||||
|
VipsThumbnail parent_object;
|
||||||
|
|
||||||
|
VipsStreamInput *input;
|
||||||
|
char *option_string;
|
||||||
|
} VipsThumbnailStream;
|
||||||
|
|
||||||
|
typedef VipsThumbnailClass VipsThumbnailStreamClass;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE( VipsThumbnailStream, vips_thumbnail_stream,
|
||||||
|
vips_thumbnail_get_type() );
|
||||||
|
|
||||||
|
/* Get the info from a stream.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
vips_thumbnail_stream_get_info( VipsThumbnail *thumbnail )
|
||||||
|
{
|
||||||
|
VipsThumbnailStream *stream = (VipsThumbnailStream *) thumbnail;
|
||||||
|
|
||||||
|
VipsImage *image;
|
||||||
|
|
||||||
|
g_info( "thumbnailing stream" );
|
||||||
|
|
||||||
|
if( !(thumbnail->loader = vips_foreign_find_load_stream(
|
||||||
|
stream->input )) ||
|
||||||
|
!(image = vips_image_new_from_stream( stream->input,
|
||||||
|
stream->option_string, NULL )) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
vips_thumbnail_read_header( thumbnail, image );
|
||||||
|
|
||||||
|
g_object_unref( image );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open an image, scaling as appropriate.
|
||||||
|
*/
|
||||||
|
static VipsImage *
|
||||||
|
vips_thumbnail_stream_open( VipsThumbnail *thumbnail, double factor )
|
||||||
|
{
|
||||||
|
VipsThumbnailStream *stream = (VipsThumbnailStream *) thumbnail;
|
||||||
|
|
||||||
|
if( vips_isprefix( "VipsForeignLoadJpeg", thumbnail->loader ) ) {
|
||||||
|
return( vips_image_new_from_stream(
|
||||||
|
stream->input,
|
||||||
|
stream->option_string,
|
||||||
|
"access", VIPS_ACCESS_SEQUENTIAL,
|
||||||
|
"shrink", (int) factor,
|
||||||
|
NULL ) );
|
||||||
|
}
|
||||||
|
else if( vips_isprefix( "VipsForeignLoadOpenslide",
|
||||||
|
thumbnail->loader ) ) {
|
||||||
|
return( vips_image_new_from_stream(
|
||||||
|
stream->input,
|
||||||
|
stream->option_string,
|
||||||
|
"access", VIPS_ACCESS_SEQUENTIAL,
|
||||||
|
"level", (int) factor,
|
||||||
|
NULL ) );
|
||||||
|
}
|
||||||
|
else if( vips_isprefix( "VipsForeignLoadPdf", thumbnail->loader ) ||
|
||||||
|
vips_isprefix( "VipsForeignLoadSvg", thumbnail->loader ) ||
|
||||||
|
vips_isprefix( "VipsForeignLoadWebp", thumbnail->loader ) ) {
|
||||||
|
return( vips_image_new_from_stream(
|
||||||
|
stream->input,
|
||||||
|
stream->option_string,
|
||||||
|
"access", VIPS_ACCESS_SEQUENTIAL,
|
||||||
|
"scale", 1.0 / factor,
|
||||||
|
NULL ) );
|
||||||
|
}
|
||||||
|
else if( vips_isprefix( "VipsForeignLoadTiff", thumbnail->loader ) ) {
|
||||||
|
return( vips_image_new_from_stream(
|
||||||
|
stream->input,
|
||||||
|
stream->option_string,
|
||||||
|
"access", VIPS_ACCESS_SEQUENTIAL,
|
||||||
|
"page", (int) factor,
|
||||||
|
NULL ) );
|
||||||
|
}
|
||||||
|
else if( vips_isprefix( "VipsForeignLoadHeif", thumbnail->loader ) ) {
|
||||||
|
return( vips_image_new_from_stream(
|
||||||
|
stream->input,
|
||||||
|
stream->option_string,
|
||||||
|
"access", VIPS_ACCESS_SEQUENTIAL,
|
||||||
|
"thumbnail", (int) factor,
|
||||||
|
NULL ) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return( vips_image_new_from_stream(
|
||||||
|
stream->input,
|
||||||
|
stream->option_string,
|
||||||
|
"access", VIPS_ACCESS_SEQUENTIAL,
|
||||||
|
NULL ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_thumbnail_stream_class_init( VipsThumbnailClass *class )
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||||
|
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
|
||||||
|
VipsThumbnailClass *thumbnail_class = VIPS_THUMBNAIL_CLASS( class );
|
||||||
|
|
||||||
|
gobject_class->set_property = vips_object_set_property;
|
||||||
|
gobject_class->get_property = vips_object_get_property;
|
||||||
|
|
||||||
|
vobject_class->nickname = "thumbnail_stream";
|
||||||
|
vobject_class->description = _( "generate thumbnail from stream" );
|
||||||
|
|
||||||
|
thumbnail_class->get_info = vips_thumbnail_stream_get_info;
|
||||||
|
thumbnail_class->open = vips_thumbnail_stream_open;
|
||||||
|
|
||||||
|
VIPS_ARG_OBJECT( class, "input", 1,
|
||||||
|
_( "Input" ),
|
||||||
|
_( "Stream to load from" ),
|
||||||
|
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||||
|
G_STRUCT_OFFSET( VipsThumbnailStream, input ),
|
||||||
|
VIPS_TYPE_STREAM_INPUT );
|
||||||
|
|
||||||
|
VIPS_ARG_STRING( class, "option_string", 20,
|
||||||
|
_( "Extra options" ),
|
||||||
|
_( "Options that are passed on to the underlying loader" ),
|
||||||
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||||
|
G_STRUCT_OFFSET( VipsThumbnailStream, option_string ),
|
||||||
|
"" );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_thumbnail_stream_init( VipsThumbnailStream *stream )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vips_thumbnail_stream:
|
||||||
|
* @input: stream to thumbnail
|
||||||
|
* @out: (out): output image
|
||||||
|
* @width: target width in pixels
|
||||||
|
* @...: %NULL-terminated list of optional named arguments
|
||||||
|
*
|
||||||
|
* Optional arguments:
|
||||||
|
*
|
||||||
|
* * @height: %gint, target height in pixels
|
||||||
|
* * @size: #VipsSize, upsize, downsize, both or force
|
||||||
|
* * @no_rotate: %gboolean, don't rotate upright using orientation tag
|
||||||
|
* * @crop: #VipsInteresting, shrink and crop to fill target
|
||||||
|
* * @linear: %gboolean, perform shrink in linear light
|
||||||
|
* * @import_profile: %gchararray, fallback import ICC profile
|
||||||
|
* * @export_profile: %gchararray, export ICC profile
|
||||||
|
* * @intent: #VipsIntent, rendering intent
|
||||||
|
*
|
||||||
|
* Exacty as vips_thumbnail(), but read from a stream.
|
||||||
|
*
|
||||||
|
* See also: vips_thumbnail().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
vips_thumbnail_stream( VipsStreamInput *input, VipsImage **out, int width, ... )
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
va_start( ap, width );
|
||||||
|
result = vips_call_split( "thumbnail_stream", ap, input, out, width );
|
||||||
|
va_end( ap );
|
||||||
|
|
||||||
|
return( result );
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct _VipsThumbnailImage {
|
typedef struct _VipsThumbnailImage {
|
||||||
VipsThumbnail parent_object;
|
VipsThumbnail parent_object;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue