From b405047132ba0f240c5e91a9223147732c016070 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 4 Jun 2013 13:25:38 +0100 Subject: [PATCH] im_system*() -> a class vips_system() is a bit more flexible too --- ChangeLog | 3 +- libvips/conversion/Makefile.am | 2 - libvips/conversion/im_system.c | 122 ---------- libvips/conversion/im_system_image.c | 171 -------------- libvips/deprecated/vips7compat.c | 41 ++++ libvips/include/vips/conversion.h | 7 - libvips/include/vips/image.h | 3 + libvips/include/vips/vips7compat.h | 5 + libvips/iofuncs/Makefile.am | 1 + libvips/iofuncs/init.c | 3 + libvips/iofuncs/system.c | 320 +++++++++++++++++++++++++++ po/POTFILES.in | 3 +- 12 files changed, 376 insertions(+), 305 deletions(-) delete mode 100644 libvips/conversion/im_system.c delete mode 100644 libvips/conversion/im_system_image.c create mode 100644 libvips/iofuncs/system.c diff --git a/ChangeLog b/ChangeLog index 8b78b523..25f09a3e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,7 +4,8 @@ it's cheap so caching doesn't help anyway - auto rshift down to 8 bits on save, if necessary - im_gaussnoise(), im_copy_file(), im_grid(), im_scale(), im_scaleps(), - im_wrap(), im_rotquad(), im_zoom(), im_subsample(), im_msb() , im_text() + im_wrap(), im_rotquad(), im_zoom(), im_subsample(), im_msb(), im_text(), + im_system(), im_system_image() redone as classes - add --angle option to dzsave diff --git a/libvips/conversion/Makefile.am b/libvips/conversion/Makefile.am index 1b5e6c35..c6e3ca7a 100644 --- a/libvips/conversion/Makefile.am +++ b/libvips/conversion/Makefile.am @@ -32,8 +32,6 @@ libconversion_la_SOURCES = \ scale.c \ wrap.c \ subsample.c \ - im_system.c \ - im_system_image.c \ text.c \ zoom.c diff --git a/libvips/conversion/im_system.c b/libvips/conversion/im_system.c deleted file mode 100644 index f824405d..00000000 --- a/libvips/conversion/im_system.c +++ /dev/null @@ -1,122 +0,0 @@ -/* im_system(): run a command on an image - * - * 7/3/00 JC - * - hacked it in - * 21/10/02 JC - * - use mktemp() if mkstemp() is not available - * 10/3/03 JC - * - out can be NULL - * 23/12/04 - * - use g_mkstemp() - * 8/9/09 - * - add .v suffix (thanks Roland) - * - use vipsbuf - * - rewrite to make it simpler - * 2/2/10 - * - gtkdoc - */ - -/* - - This file is part of VIPS. - - VIPS is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include -#include - -#ifdef HAVE_UNISTD_H -#include -#endif /*HAVE_UNISTD_H*/ -#include -#include -#include - -#include - -#define IM_MAX_STRSIZE (4096) - -/** - * im_system: - * @im: image to run command on - * @cmd: command to run - * @out: stdout of command is returned here - * - * im_system() runs a command on an image, returning the command's output as a - * string. The command is executed with popen(), the first '%%s' in the - * command being substituted for a filename. - * - * If the IMAGE is a file on disc, then the filename will be the name of the - * real file. If the image is in memory, or the result of a computation, - * then a new file is created in the temporary area called something like - * "vips_XXXXXX.v", and that filename given to the command. The file is - * deleted when the command finishes. - * - * See im_system_image() for details on how VIPS selects a temporary - * directory. - * - * In all cases, @log must be freed with im_free(). - * - * See also: im_system_image(). - * - * Returns: 0 on success, -1 on error - */ -int -im_system( IMAGE *im, const char *cmd, char **out ) -{ - FILE *fp; - - if( !im_isfile( im ) ) { - IMAGE *disc; - - if( !(disc = im__open_temp( "%s.v" )) ) - return( -1 ); - if( im_copy( im, disc ) || - im_system( disc, cmd, out ) ) { - im_close( disc ); - return( -1 ); - } - im_close( disc ); - } - else if( (fp = im_popenf( cmd, "r", im->filename )) ) { - char line[IM_MAX_STRSIZE]; - char txt[IM_MAX_STRSIZE]; - VipsBuf buf = VIPS_BUF_STATIC( txt ); - - while( fgets( line, IM_MAX_STRSIZE, fp ) ) - if( !vips_buf_appends( &buf, line ) ) - break; - pclose( fp ); - - if( out ) - *out = im_strdup( NULL, vips_buf_all( &buf ) ); - } - - return( 0 ); -} diff --git a/libvips/conversion/im_system_image.c b/libvips/conversion/im_system_image.c deleted file mode 100644 index 660c07d8..00000000 --- a/libvips/conversion/im_system_image.c +++ /dev/null @@ -1,171 +0,0 @@ -/* im_system_image(): run a command on an image, get an image result - * - * 8/1/09 - * - from im_system() - * 2/2/10 - * - gtkdoc - */ - -/* - - This file is part of VIPS. - - VIPS is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include -#include - -#ifdef HAVE_UNISTD_H -#include -#endif /*HAVE_UNISTD_H*/ -#include -#include -#include - -#include - -#define IM_MAX_STRSIZE (4096) - -static int -system_image( IMAGE *im, - IMAGE *in_image, char *out_name, const char *cmd_format, - char **log ) -{ - const char *in_name = in_image->filename; - FILE *fp; - char line[IM_MAX_STRSIZE]; - char txt[IM_MAX_STRSIZE]; - VipsBuf buf = VIPS_BUF_STATIC( txt ); - int result; - - if( im_copy( im, in_image ) || - !(fp = im_popenf( cmd_format, "r", in_name, out_name )) ) - return( -1 ); - - while( fgets( line, IM_MAX_STRSIZE, fp ) ) - if( !vips_buf_appends( &buf, line ) ) - break; - - if( (result = pclose( fp )) ) - im_error( "im_system_image", - _( "command failed: \"%s\"" ), cmd_format ); - - if( log ) - *log = im_strdup( NULL, vips_buf_all( &buf ) ); - - return( result ); -} - -/** - * im_system_image: - * @im: image to run command on - * @in_format: write input file like this - * @out_format: write output filename like this - * @cmd_format: command to run - * @log: stdout of command is returned here - * - * im_system_image() runs a command, passing an image in and getting an image - * back. The command's stdout is returned in @log. - * - * First, @im is written to a file. The filename is formed by substituting - * something like "vips-49857-1" for the first %%s in @in_format, then - * prepending "/tmp". If the environment variable TMPDIR is defined, it - * can be used to set a different temporary directory. If @in_format is - * something like "%%s.png", the file will be written in PNG format. - * - * On Windows, if the environment variable TMPDIR is not defined, VIPS calls - * GetTempPath() to get the user's preferred temporary area. If that fails, it - * defaults to C:\temp. - * - * Next an output filename is created in the same way using @out_format. The - * command string to run is made by substituting the first %%s in @cmd_format - * for the name of the input file and the second %%s for the output filename. - * - * The command is executed with popen() and the output captured in @log. If - * the command fails, the temporary files are deleted and im_system_image() - * returns NULL. @log is still set. - * - * If the command succeeds, the input file is deleted, the output file opened, - * and returned. Closing the output image will automatically delete the file. - * - * In all cases, @log must be freed with im_free(). - * - * For example, this call will run the ImageMagick convert program on an - * image, using JPEG files to pass images into and out of the convert command. - * - * |[ - * im_system_image( in, out, - * "%s.jpg", "%s.jpg", "convert %s -swirl 45 %s", - * &log ) - * ]| - * - * See also: im_system(). - * - * Returns: (transfer full): an image on success, NULL on error - */ -IMAGE * -im_system_image( IMAGE *im, - const char *in_format, const char *out_format, const char *cmd_format, - char **log ) -{ - IMAGE *in_image; - char *out_name; - IMAGE *out; - - if( log ) - *log = NULL; - - if( !(in_image = im__open_temp( in_format )) ) - return( NULL ); - if( !(out_name = im__temp_name( out_format )) ) { - im_close( in_image ); - return( NULL ); - } - - if( system_image( im, in_image, out_name, cmd_format, log ) ) { - im_close( in_image ); - g_free( out_name ); - g_unlink( out_name ); - - return( NULL ); - } - im_close( in_image ); - - if( !(out = im_open( out_name, "r" )) ) { - g_free( out_name ); - g_unlink( out_name ); - - return( NULL ); - } - g_free( out_name ); - - vips_image_set_delete_on_close( out, TRUE ); - - return( out ); -} diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index 13a28bab..43046c35 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -1581,6 +1581,47 @@ im_text( IMAGE *out, const char *text, const char *font, return( 0 ); } +int +im_system( VipsImage *im, const char *cmd, char **out ) +{ + char *str; + + if( vips_system( cmd, + "in", im, + "in_format", "%s.v", + "log", &str, + NULL ) ) + return( -1 ); + + if( out ) + *out = str; + + return( 0 ); +} + +VipsImage * +im_system_image( VipsImage *im, + const char *in_format, const char *out_format, const char *cmd_format, + char **log ) +{ + char *str; + VipsImage *out; + + if( vips_system( cmd_format, + "in", im, + "out", &out, + "in_format", in_format, + "out_format", out_format, + "log", &str, + NULL ) ) + return( NULL ); + + if( log ) + *log = str; + + return( out ); +} + int im_wrap( IMAGE *in, IMAGE *out, int x, int y ) { diff --git a/libvips/include/vips/conversion.h b/libvips/include/vips/conversion.h index 70cadab7..7e7859a3 100644 --- a/libvips/include/vips/conversion.h +++ b/libvips/include/vips/conversion.h @@ -265,17 +265,10 @@ int vips_flatten( VipsImage *in, VipsImage **out, ... ) - - int im_falsecolour( VipsImage *in, VipsImage *out ); int im_insertset( VipsImage *main, VipsImage *sub, VipsImage *out, int n, int *x, int *y ); -int im_system( VipsImage *im, const char *cmd, char **out ); -VipsImage *im_system_image( VipsImage *im, - const char *in_format, const char *out_format, const char *cmd_format, - char **log ); - #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/include/vips/image.h b/libvips/include/vips/image.h index 81dc3cd5..bb85fd66 100644 --- a/libvips/include/vips/image.h +++ b/libvips/include/vips/image.h @@ -530,6 +530,9 @@ gboolean vips_band_format_is8bit( VipsBandFormat format ); gboolean vips_band_format_isfloat( VipsBandFormat format ); gboolean vips_band_format_iscomplex( VipsBandFormat format ); +int vips_system( const char *cmd_format, ... ) + __attribute__((sentinel)); + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index 098d4d8d..d4bf875e 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -722,6 +722,11 @@ int im_subsample( VipsImage *in, VipsImage *out, int xshrink, int yshrink ); int im_text( VipsImage *out, const char *text, const char *font, int width, int alignment, int dpi ); +int im_system( VipsImage *im, const char *cmd, char **out ); +VipsImage *im_system_image( VipsImage *im, + const char *in_format, const char *out_format, const char *cmd_format, + char **log ); + int im_c2amph( VipsImage *in, VipsImage *out ); int im_c2rect( VipsImage *in, VipsImage *out ); int im_c2imag( VipsImage *in, VipsImage *out ); diff --git a/libvips/iofuncs/Makefile.am b/libvips/iofuncs/Makefile.am index e1a6a697..586a65f1 100644 --- a/libvips/iofuncs/Makefile.am +++ b/libvips/iofuncs/Makefile.am @@ -29,6 +29,7 @@ libiofuncs_la_SOURCES = \ buf.c \ window.c \ vector.c \ + system.c \ buffer.c EXTRA_DIST = enumtemplate diff --git a/libvips/iofuncs/init.c b/libvips/iofuncs/init.c index 4346c2ee..26965dd6 100644 --- a/libvips/iofuncs/init.c +++ b/libvips/iofuncs/init.c @@ -168,6 +168,8 @@ vips_get_argv0( void ) int vips_init( const char *argv0 ) { + extern GType vips_system_get_type( void ); + static gboolean started = FALSE; static gboolean done = FALSE; char *prgname; @@ -238,6 +240,7 @@ vips_init( const char *argv0 ) /* Start up packages. */ + (void) vips_system_get_type(); vips_arithmetic_operation_init(); vips_conversion_operation_init(); vips_foreign_operation_init(); diff --git a/libvips/iofuncs/system.c b/libvips/iofuncs/system.c new file mode 100644 index 00000000..2cb9da06 --- /dev/null +++ b/libvips/iofuncs/system.c @@ -0,0 +1,320 @@ +/* vips_system(): run a command on an image + * + * 7/3/00 JC + * - hacked it in + * 21/10/02 JC + * - use mktemp() if mkstemp() is not available + * 10/3/03 JC + * - out can be NULL + * 23/12/04 + * - use g_mkstemp() + * 8/9/09 + * - add .v suffix (thanks Roland) + * - use vipsbuf + * - rewrite to make it simpler + * 2/2/10 + * - gtkdoc + * 4/6/13 + * - redo as a class + * - input and output images are now optional + */ + +/* + + This file is part of VIPS. + + VIPS is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA + + */ + +/* + + These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /*HAVE_CONFIG_H*/ +#include + +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif /*HAVE_UNISTD_H*/ +#include +#include +#include + +#include + +#define MAX_STRSIZE (4096) + +typedef struct _VipsSystem { + VipsOperation parent_instance; + + VipsImage *in; + VipsImage *out; + char *cmd_format; + char *in_format; + char *out_format; + char *log; + + /* Set to delete in_name on close. + */ + gboolean delete_on_close; + char *in_name; + + char *out_name; + +} VipsSystem; + +typedef VipsOperationClass VipsSystemClass; + +G_DEFINE_TYPE( VipsSystem, vips_system, VIPS_TYPE_OPERATION ); + +static void +vips_system_dispose( GObject *gobject ) +{ + VipsSystem *system = (VipsSystem *) gobject; + + if( system->delete_on_close && + system->in_name ) + g_unlink( system->in_name ); + VIPS_FREE( system->in_name ); + system->delete_on_close = FALSE; + + VIPS_FREE( system->out_name ); + + G_OBJECT_CLASS( vips_system_parent_class )->dispose( gobject ); +} + +static int +vips_system_build( VipsObject *object ) +{ + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); + VipsSystem *system = (VipsSystem *) object; + + FILE *fp; + char line[MAX_STRSIZE]; + char txt[MAX_STRSIZE]; + VipsBuf buf = VIPS_BUF_STATIC( txt ); + int result; + + if( VIPS_OBJECT_CLASS( vips_system_parent_class )->build( object ) ) + return( -1 ); + + /* Write the input image to a file. We must always make a copy of the + * file, even if this is a disc file already, in case the command + * needs a different format. + */ + if( system->in ) { + char *in_format = system->in_format ? + system->in_format : "%s.tif"; + + if( !(system->in_name = vips__temp_name( in_format )) ) + return( -1 ); + if( vips_image_write_to_file( system->in, system->in_name ) ) + return( -1 ); + system->delete_on_close = TRUE; + } + + /* Make the output filename. + */ + if( system->out_format && + !(system->out_name = vips__temp_name( system->out_format )) ) + return( -1 ); + + if( system->in_name ) { + if( !(fp = vips_popenf( system->cmd_format, "r", + system->in_name, system->out_name )) ) + return( -1 ); + } + else { + if( !(fp = vips_popenf( system->cmd_format, "r", + system->out_name )) ) + return( -1 ); + } + + while( fgets( line, MAX_STRSIZE, fp ) ) + if( !vips_buf_appends( &buf, line ) ) + break; + + g_object_set( system, "log", vips_buf_all( &buf ), NULL ); + + if( (result = pclose( fp )) ) { + vips_error( class->nickname, + _( "command failed: \"%s\"" ), system->cmd_format ); + return( -1 ); + } + + if( system->out_format ) { + VipsImage *out; + + if( !(out = vips_image_new_from_file( system->out_name )) ) + return( -1 ); + vips_image_set_delete_on_close( out, TRUE ); + + g_object_set( system, "out", out, NULL ); + } + + return( 0 ); +} + +static void +vips_system_class_init( VipsSystemClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); + + gobject_class->dispose = vips_system_dispose; + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + vobject_class->nickname = "system"; + vobject_class->description = _( "run an external command" ); + vobject_class->build = vips_system_build; + + VIPS_ARG_IMAGE( class, "in", 0, + _( "Input" ), + _( "Input image" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsSystem, in ) ); + + VIPS_ARG_IMAGE( class, "out", 1, + _( "Output" ), + _( "Output image" ), + VIPS_ARGUMENT_OPTIONAL_OUTPUT, + G_STRUCT_OFFSET( VipsSystem, out ) ); + + VIPS_ARG_STRING( class, "cmd_format", 2, + _( "Command" ), + _( "Command to run" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsSystem, cmd_format ), + NULL ); + + VIPS_ARG_STRING( class, "in_format", 2, + _( "Input format" ), + _( "Format for input filename" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsSystem, in_format ), + NULL ); + + VIPS_ARG_STRING( class, "out_format", 2, + _( "Output format" ), + _( "Format for output filename" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsSystem, out_format ), + NULL ); + + VIPS_ARG_STRING( class, "log", 2, + _( "Log" ), + _( "Command log" ), + VIPS_ARGUMENT_OPTIONAL_OUTPUT, + G_STRUCT_OFFSET( VipsSystem, log ), + NULL ); + +} + +static void +vips_system_init( VipsSystem *system ) +{ +} + +/** + * vips_system: + * @cmd_format: command to run + * @...: %NULL-terminated list of optional named arguments + * + * Optional arguments: + * + * @in: input image + * @out: output image + * @in_format: write input file like this + * @out_format: write output filename like this + * @log: stdout of command is returned here + * + * vips_system() runs a command, optionally passing an image in and + * optionally getting an image + * back. The command's stdout is returned in @log. + * + * First, if @in is set, it is written to a file. The filename is formed by + * substituting something like "vips-49857-1" for the first %%s in @in_format, + * then + * prepending "/tmp". If the environment variable TMPDIR is defined, it + * can be used to set a different temporary directory. + * + * On Windows, if the environment variable TMPDIR is not defined, VIPS calls + * GetTempPath() to get the user's preferred temporary area. If that fails, it + * defaults to C:\temp. + * + * If @in_format is + * something like "%%s.png", the file will be written in PNG format. By + * default, @in_format is "%%s.tif". + * + * If @out_format is set, an output filename is formed in the same way. + * + * The + * command string to run is made by substituting the first %%s in @cmd_format + * for the name of the input file, if @in is set, and the second %%s for the + * output filename, if set. + * + * The command is executed with popen() and the output captured in @log. + * + * After the command finishes, if @out_format is set, the output image is + * opened and returned in @out. + * Closing the output image will automatically delete the output file. + * + * Finally the input images are deleted. + * + * For example, this call will run the ImageMagick convert program on an + * image, using JPEG files to pass images into and out of the convert command. + * + * |[ + * VipsImage *in; + * VipsImage *out; + * char *log; + * + * if (vips_system ("convert %s -swirl 45 %s", + * "in", in, + * "out", &out, + * "in_format", "%s.jpg", + * "out_format", "%s.jpg", + * "log", &log, + * NULL)) + * error ... + * ]| + * + * Returns: 0 on success, -1 on failure. + */ +int +vips_system( const char *cmd_format, ... ) +{ + va_list ap; + int result; + + va_start( ap, cmd_format ); + result = vips_call_split( "system", ap, cmd_format ); + va_end( ap ); + + return( result ); +} + + + diff --git a/po/POTFILES.in b/po/POTFILES.in index a56c43f7..24645359 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -55,7 +55,6 @@ libvips/colour/scRGB2sRGB.c libvips/conversion/flip.c libvips/conversion/bandmean.c libvips/conversion/zoom.c -libvips/conversion/im_system.c libvips/conversion/gaussnoise.c libvips/conversion/bandary.c libvips/conversion/cast.c @@ -78,7 +77,6 @@ libvips/conversion/conver_dispatch.c libvips/conversion/wrap.c libvips/conversion/insert.c libvips/conversion/tilecache.c -libvips/conversion/im_system_image.c libvips/conversion/embed.c libvips/conversion/cache.c libvips/conversion/im_falsecolour.c @@ -204,6 +202,7 @@ libvips/iofuncs/object.c libvips/iofuncs/threadpool.c libvips/iofuncs/memory.c libvips/iofuncs/cache.c +libvips/iofuncs/system.c libvips/morphology/im_cntlines.c libvips/morphology/im_profile.c libvips/morphology/morph_dispatch.c