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));
|
||||
int vips_thumbnail_image( VipsImage *in, VipsImage **out, int width, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_thumbnail_stream( VipsStreamInput *input, VipsImage **out,
|
||||
int width, ... )
|
||||
__attribute__((sentinel));
|
||||
|
||||
int vips_similarity( VipsImage *in, VipsImage **out, ... )
|
||||
__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_memory( const void *data,
|
||||
size_t size );
|
||||
VipsStreamInput *vips_stream_input_new_from_options( const char *options );
|
||||
|
||||
ssize_t vips_stream_input_read( VipsStreamInput *input,
|
||||
unsigned char *data, size_t length );
|
||||
|
|
|
@ -1889,18 +1889,11 @@ vips_object_set_argument_from_string( VipsObject *object,
|
|||
char filename[VIPS_PATH_MAX];
|
||||
char option_string[VIPS_PATH_MAX];
|
||||
|
||||
if( !value ) {
|
||||
vips_object_no_value( object, name );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
if( VIPS_IS_OPERATION( object ) )
|
||||
flags = vips_operation_get_flags(
|
||||
VIPS_OPERATION( object ) );
|
||||
|
||||
/* Read the filename.
|
||||
*/
|
||||
if( flags &
|
||||
(VIPS_OPERATION_SEQUENTIAL_UNBUFFERED |
|
||||
VIPS_OPERATION_SEQUENTIAL) )
|
||||
|
@ -1908,6 +1901,10 @@ vips_object_set_argument_from_string( VipsObject *object,
|
|||
else
|
||||
access = VIPS_ACCESS_RANDOM;
|
||||
|
||||
if( !value ) {
|
||||
vips_object_no_value( object, name );
|
||||
return( -1 );
|
||||
}
|
||||
vips__filename_split8( value, filename, option_string );
|
||||
|
||||
if( strcmp( "stdin", filename ) == 0 ) {
|
||||
|
@ -1940,6 +1937,25 @@ vips_object_set_argument_from_string( VipsObject *object,
|
|||
*/
|
||||
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 ) ) {
|
||||
/* 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
|
||||
|
|
|
@ -1245,7 +1245,8 @@ typedef struct _VipsCall {
|
|||
static const char *
|
||||
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,
|
||||
"%s", _( "too few arguments" ) );
|
||||
return( NULL );
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
/* TODO
|
||||
*
|
||||
* - minimise support, and reenable jpg test_descriptors
|
||||
* - filename encoding
|
||||
* - memory output
|
||||
* - add mmapable descriptors
|
||||
|
@ -322,7 +323,7 @@ vips_stream_input_class_init( VipsStreamInputClass *class )
|
|||
gobject_class->set_property = vips_object_set_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->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.
|
||||
*
|
||||
* #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
|
||||
*/
|
||||
VipsStreamInput *
|
||||
vips_stream_input_new_from_blob( VipsBlob *blob )
|
||||
{
|
||||
VipsStreamInput *stream;
|
||||
VipsStreamInput *input;
|
||||
|
||||
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,
|
||||
"blob", blob,
|
||||
NULL ) );
|
||||
|
||||
if( vips_object_build( VIPS_OBJECT( stream ) ) ) {
|
||||
VIPS_UNREF( stream );
|
||||
if( vips_object_build( VIPS_OBJECT( input ) ) ) {
|
||||
VIPS_UNREF( input );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
return( stream );
|
||||
return( input );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_stream_input_new_from_memory:
|
||||
* @buf: memory area to load
|
||||
* @len: size of memory area
|
||||
* @data: memory area to load
|
||||
* @length: size of memory area
|
||||
*
|
||||
* Create a stream attached to an area of memory.
|
||||
*
|
||||
* You must not free @buf 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().
|
||||
* You must not free @data while the stream is active.
|
||||
*
|
||||
* Returns: a new #VipsStream
|
||||
*/
|
||||
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;
|
||||
|
||||
VIPS_DEBUG_MSG( "vips_stream_input_new_from_buffer: %p, size = %zd\n",
|
||||
data, size );
|
||||
VIPS_DEBUG_MSG( "vips_stream_input_new_from_buffer: "
|
||||
"%p, length = %zd\n", data, length );
|
||||
|
||||
/* 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 ) );
|
||||
|
||||
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
|
||||
|
@ -696,7 +714,7 @@ vips_stream_output_class_init( VipsStreamOutputClass *class )
|
|||
gobject_class->set_property = vips_object_set_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->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
|
||||
* 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 to save to" ),
|
||||
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_buffer_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_shrink_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_buffer_get_type();
|
||||
vips_thumbnail_image_get_type();
|
||||
vips_thumbnail_stream_get_type();
|
||||
vips_mapim_get_type();
|
||||
vips_shrink_get_type();
|
||||
vips_shrinkh_get_type();
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
* - prevent over-pre-shrink in thumbnail
|
||||
* 30/9/19
|
||||
* - 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 );
|
||||
}
|
||||
|
||||
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 {
|
||||
VipsThumbnail parent_object;
|
||||
|
||||
|
|
Loading…
Reference in New Issue