From 4d3f66fe333f6b05ccb6f9967f4c0dea4595a340 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Sat, 12 Oct 2019 14:12:01 +0100 Subject: [PATCH] add stdout write this now works: $ vips invert k2.jpg .jpg | vips invert stdin x.jpg "stdin" means read from stdin, ".jpg" means write to stdout in JPG format --- libvips/foreign/foreign.c | 54 ++++++++++++++++++++++++++++++++++ libvips/include/vips/foreign.h | 1 + libvips/include/vips/image.h | 3 ++ libvips/iofuncs/image.c | 45 ++++++++++++++++++++++++++++ libvips/iofuncs/object.c | 48 +++++++++++++++++++++++------- libvips/iofuncs/stream.c | 1 - 6 files changed, 140 insertions(+), 12 deletions(-) diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index 0a6c580f..2e777a93 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -1865,6 +1865,58 @@ vips_foreign_save( VipsImage *in, const char *name, ... ) return( result ); } +/* Can thsi class write this filetype to a stream? + */ +static void * +vips_foreign_find_save_stream_sub( VipsForeignSaveClass *save_class, + const char *suffix ) +{ + VipsObjectClass *object_class = VIPS_OBJECT_CLASS( save_class ); + VipsForeignClass *class = VIPS_FOREIGN_CLASS( save_class ); + + printf( "testing %s for %s\n", object_class->nickname, suffix ); + + if( class->suffs && + vips_ispostfix( object_class->nickname, "_stream" ) && + vips_filename_suffix_match( suffix, class->suffs ) ) + return( save_class ); + + return( NULL ); +} + +/** + * vips_foreign_find_save_stream: + * @suffix: format to find a saver for + * + * Searches for an operation you could use to write to a stream in @suffix + * format. + * + * See also: vips_image_write_to_buffer(). + * + * Returns: the name of an operation on success, %NULL on error + */ +const char * +vips_foreign_find_save_stream( const char *name ) +{ + char suffix[VIPS_PATH_MAX]; + char option_string[VIPS_PATH_MAX]; + VipsForeignSaveClass *save_class; + + vips__filename_split8( name, suffix, option_string ); + + if( !(save_class = (VipsForeignSaveClass *) vips_foreign_map( + "VipsForeignSave", + (VipsSListMap2Fn) vips_foreign_find_save_stream_sub, + (void *) suffix, NULL )) ) { + vips_error( "VipsForeignSave", + _( "\"%s\" is not a known stream format" ), name ); + + return( NULL ); + } + + return( G_OBJECT_CLASS_NAME( save_class ) ); +} + /* Can we write this buffer with this file type? */ static void * @@ -1946,6 +1998,7 @@ vips_foreign_operation_init( void ) extern GType vips_foreign_load_jpeg_stream_get_type( void ); extern GType vips_foreign_save_jpeg_file_get_type( void ); extern GType vips_foreign_save_jpeg_buffer_get_type( void ); + extern GType vips_foreign_save_jpeg_stream_get_type( void ); extern GType vips_foreign_save_jpeg_mime_get_type( void ); extern GType vips_foreign_load_tiff_file_get_type( void ); extern GType vips_foreign_load_tiff_buffer_get_type( void ); @@ -2058,6 +2111,7 @@ vips_foreign_operation_init( void ) vips_foreign_load_jpeg_stream_get_type(); vips_foreign_save_jpeg_file_get_type(); vips_foreign_save_jpeg_buffer_get_type(); + vips_foreign_save_jpeg_stream_get_type(); vips_foreign_save_jpeg_mime_get_type(); #endif /*HAVE_JPEG*/ diff --git a/libvips/include/vips/foreign.h b/libvips/include/vips/foreign.h index 772dd12d..f080bce8 100644 --- a/libvips/include/vips/foreign.h +++ b/libvips/include/vips/foreign.h @@ -354,6 +354,7 @@ GType vips_foreign_save_get_type(void); const char *vips_foreign_find_save( const char *filename ); gchar **vips_foreign_get_suffixes( void ); const char *vips_foreign_find_save_buffer( const char *suffix ); +const char *vips_foreign_find_save_stream( const char *suffix ); int vips_vipsload( const char *filename, VipsImage **out, ... ) __attribute__((sentinel)); diff --git a/libvips/include/vips/image.h b/libvips/include/vips/image.h index 2e9b9992..a7b0cccc 100644 --- a/libvips/include/vips/image.h +++ b/libvips/include/vips/image.h @@ -473,6 +473,9 @@ int vips_image_write_to_file( VipsImage *image, const char *name, ... ) int vips_image_write_to_buffer( VipsImage *in, const char *suffix, void **buf, size_t *size, ... ) __attribute__((sentinel)); +int vips_image_write_to_stream( VipsImage *in, + const char *suffix, VipsStreamOutput *output, ... ) + __attribute__((sentinel)); void *vips_image_write_to_memory( VipsImage *in, size_t *size ); int vips_image_decode_predict( VipsImage *in, diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c index d979dea6..297fc180 100644 --- a/libvips/iofuncs/image.c +++ b/libvips/iofuncs/image.c @@ -2704,6 +2704,51 @@ vips_image_write_to_buffer( VipsImage *in, return( 0 ); } +/** + * vips_image_write_to_stream: (method) + * @in: image to write + * @suffix: format to write + * @output: stream to write to + * @...: %NULL-terminated list of optional named arguments + * + * Writes @in to @output in format @suffix. + * + * Save options may be appended to @suffix as "[name=value,...]" or given as + * a NULL-terminated list of name-value pairs at the end of the arguments. + * Options given in the function call override options given in the filename. + * + * You can call the various save operations directly if you wish, see + * vips_jpegsave_stream(), for example. + * + * See also: vips_image_write_to_file(). + * + * Returns: 0 on success, -1 on error + */ +int +vips_image_write_to_stream( VipsImage *in, + const char *suffix, VipsStreamOutput *output, ... ) +{ + char filename[VIPS_PATH_MAX]; + char option_string[VIPS_PATH_MAX]; + const char *operation_name; + va_list ap; + int result; + + vips__filename_split8( suffix, filename, option_string ); + if( !(operation_name = vips_foreign_find_save_stream( filename )) ) + return( -1 ); + + va_start( ap, output ); + result = vips_call_split_option_string( operation_name, option_string, + ap, in, output ); + va_end( ap ); + + if( result ) + return( -1 ); + + return( 0 ); +} + /** * vips_image_write_to_memory: (method) * @in: image to write diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index 5520b057..c9f0eedf 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -1886,6 +1886,8 @@ vips_object_set_argument_from_string( VipsObject *object, VipsImage *out; VipsOperationFlags flags; VipsAccess access; + char filename[VIPS_PATH_MAX]; + char option_string[VIPS_PATH_MAX]; if( !value ) { vips_object_no_value( object, name ); @@ -1906,15 +1908,16 @@ vips_object_set_argument_from_string( VipsObject *object, else access = VIPS_ACCESS_RANDOM; - /* The special filename "-" means stdin. - */ - if( strcmp( value, "-" ) == 0 ) { + vips__filename_split8( value, filename, option_string ); + + if( strcmp( "stdin", filename ) == 0 ) { VipsStreamInput *input; if( !(input = vips_stream_input_new_from_descriptor( 0 )) ) return( -1 ); - if( !(out = vips_image_new_from_stream( input, "", + if( !(out = vips_image_new_from_stream( input, + option_string, "access", access, NULL )) ) { VIPS_UNREF( input ); @@ -2185,14 +2188,37 @@ vips_object_get_argument_to_string( VipsObject *object, if( g_type_is_a( otype, VIPS_TYPE_IMAGE ) ) { VipsImage *in; -/* Pull out the image and write it. - */ - g_object_get( object, name, &in, NULL ); - if( vips_image_write_to_file( in, arg, NULL ) ) { - g_object_unref( in ); - return( -1 ); + char filename[VIPS_PATH_MAX]; + char option_string[VIPS_PATH_MAX]; + + vips__filename_split8( arg, filename, option_string ); + + if( vips_isprefix( ".", filename ) ) { + VipsStreamOutput *output; + + if( !(output = + vips_stream_output_new_from_descriptor( 1 )) ) + return( -1 ); + g_object_get( object, name, &in, NULL ); + if( vips_image_write_to_stream( in, + arg, output, NULL ) ) { + VIPS_UNREF( in ); + VIPS_UNREF( output ); + return( -1 ); + } + VIPS_UNREF( in ); + VIPS_UNREF( output ); + } + else { + /* Pull out the image and write it. + */ + g_object_get( object, name, &in, NULL ); + if( vips_image_write_to_file( in, arg, NULL ) ) { + VIPS_UNREF( in ); + return( -1 ); + } + VIPS_UNREF( in ); } - g_object_unref( in ); } else if( g_type_is_a( otype, VIPS_TYPE_OBJECT ) && (oclass = g_type_class_ref( otype )) && diff --git a/libvips/iofuncs/stream.c b/libvips/iofuncs/stream.c index 007ae7fd..f48a599b 100644 --- a/libvips/iofuncs/stream.c +++ b/libvips/iofuncs/stream.c @@ -744,7 +744,6 @@ vips_stream_output_new_from_descriptor( int descriptor ) stream = VIPS_STREAM_OUTPUT( g_object_new( VIPS_TYPE_STREAM_OUTPUT, "descriptor", descriptor, - "filename", "descriptor", NULL ) ); if( vips_object_build( VIPS_OBJECT( stream ) ) ) {