add im_system_image()

This commit is contained in:
John Cupitt 2010-01-08 16:58:44 +00:00
parent 377b76b255
commit 88779a7e3b
10 changed files with 277 additions and 63 deletions

View File

@ -11,6 +11,7 @@
repeating stuff
- im_flood() and friends rewritten, typically 4x faster
- removed --with-cimg option, added --disable-cxx
- added im_system_image() (thanks Roland)
26/11/09 started 7.20.3
- updated en_GB.po translation

19
TODO
View File

@ -16,25 +16,6 @@
for swapping ... they are asm macros so we should see a speedup
Something like:
const char *im_system_image( IMAGE *in, const char *command, char **log );
Actions:
- create two empty temporary files
- write the image to the first
- call system() on the expanded command
- capture stdout/stderr into log
- delete the temp input file
- return the output filename, or NULL if the command failed (log is still
returned in this case)
The caller would open the output file, either with im_open(), or with it's
own system (nip2 has it's own open file thing to give progress feedback and
use disc for format conversion), and be responsible for deleting the temp
output file at some point.
- can we use conv_sep to speed up the memuse benchmarks?
- move im_shrink & friends to resample?

View File

@ -32,6 +32,7 @@ libconversion_la_SOURCES = \
im_scaleps.c \
im_subsample.c \
im_system.c \
im_system_image.c \
im_tbjoin.c \
im_text.c \
im_gaussnoise.c \

View File

@ -73,7 +73,7 @@ system_vec( im_object *argv )
return( 0 );
}
static im_arg_desc system_arg_types[] = {
static im_arg_desc system_args[] = {
IM_INPUT_IMAGE( "im" ),
IM_INPUT_STRING( "command" ),
IM_OUTPUT_STRING( "output" )
@ -84,8 +84,43 @@ static im_function system_desc = {
"run command on image", /* Description */
0, /* Flags */
system_vec, /* Dispatch function */
IM_NUMBER( system_arg_types ), /* Size of arg list */
system_arg_types /* Arg list */
IM_NUMBER( system_args ), /* Size of arg list */
system_args /* Arg list */
};
static int
system_image_vec( im_object *argv )
{
IMAGE *in = argv[0];
char *in_format = argv[1];
char *out_format = argv[2];
char *cmd = argv[3];
char **log = (char **) &argv[4];
char **out_file = (char **) &argv[5];
*out_file = im_system_image( in, in_format, out_format, cmd, log );
if( !*out_file )
*out_file = im_strdup( NULL, "" );
return( 0 );
}
static im_arg_desc system_image_args[] = {
IM_INPUT_IMAGE( "im" ),
IM_INPUT_STRING( "in_format" ),
IM_INPUT_STRING( "out_format" ),
IM_INPUT_STRING( "command" ),
IM_OUTPUT_STRING( "log" ),
IM_OUTPUT_STRING( "out_file" )
};
static im_function system_image_desc = {
"im_system_image", /* Name */
"run command on image, with image output",/* Description */
0, /* Flags */
system_image_vec, /* Dispatch function */
IM_NUMBER( system_image_args ), /* Size of arg list */
system_image_args /* Arg list */
};
static int
@ -1433,6 +1468,7 @@ static im_function *conv_list[] = {
&scaleps_desc,
&subsample_desc,
&system_desc,
&system_image_desc,
&tbjoin_desc,
&text_desc,
&vips2mask_desc,

View File

@ -68,27 +68,6 @@
#define pclose(f) _pclose(f)
#endif /*OS_WIN32*/
/* Do popen(), with printf-style args.
*/
static FILE *
popenf( const char *fmt, const char *mode, ... )
{
va_list args;
char buf[IM_MAX_STRSIZE];
FILE *fp;
va_start( args, mode );
(void) im_vsnprintf( buf, IM_MAX_STRSIZE, fmt, args );
va_end( args );
if( !(fp = popen( buf, mode )) ) {
im_error( "popenf", "%s", strerror( errno ) );
return( NULL );
}
return( fp );
}
/* Run a command on an IMAGE ... copy to tmp (if necessary), run
* command on it, unlink (if we copied), return stdout from command.
*/
@ -109,12 +88,11 @@ im_system( IMAGE *im, const char *cmd, char **out )
}
im_close( disc );
}
else if( (fp = popenf( cmd, "r", im->filename )) ) {
else if( (fp = im_popenf( cmd, "r", im->filename )) ) {
char line[IM_MAX_STRSIZE];
VipsBuf buf;
char str[IM_MAX_STRSIZE];
char txt[IM_MAX_STRSIZE];
VipsBuf buf = VIPS_BUF_STATIC( txt );
vips_buf_init_static( &buf, str, IM_MAX_STRSIZE );
while( fgets( line, IM_MAX_STRSIZE, fp ) )
if( !vips_buf_appends( &buf, line ) )
break;

View File

@ -0,0 +1,155 @@
/* im_system_image(): run a command on an image, get an image result
*
* 8/1/09
* - from im_system()
*/
/*
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /*HAVE_UNISTD_H*/
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <vips/vips.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif /*WITH_DMALLOC*/
#define IM_MAX_STRSIZE (4096)
#ifdef OS_WIN32
#define popen(b,m) _popen(b,m)
#define pclose(f) _pclose(f)
#endif /*OS_WIN32*/
static int
system_image( IMAGE *im,
const char *in_name, const char *out_name, const char *cmd_format,
char **log )
{
IMAGE *disc;
FILE *fp;
char line[IM_MAX_STRSIZE];
char txt[IM_MAX_STRSIZE];
VipsBuf buf = VIPS_BUF_STATIC( txt );
int result;
if( !(disc = im_open( in_name, "w" )) )
return( -1 );
if( im_copy( im, disc ) ) {
im_close( im );
g_unlink( in_name );
return( -1 );
}
im_close( im );
if( !(fp = im_popenf( cmd_format, "r", in_name, out_name )) ) {
g_unlink( in_name );
return( -1 );
}
while( fgets( line, IM_MAX_STRSIZE, fp ) )
if( !vips_buf_appends( &buf, line ) )
break;
result = pclose( fp );
g_unlink( in_name );
if( log )
*log = im_strdup( NULL, vips_buf_all( &buf ) );
return( result );
}
/*
Run a command on an image, returning a new image.
"mycommand --dostuff %s -o %s"
have separate format strings for input and output?
"%s.jpg"
Actions:
- create two empty temporary files
- write the image to the first
- call system() on the expanded command
- capture stdout/stderr into log
- delete the temp input file
- return the output filename, or NULL if the command failed (log is still
set in this case)
The caller would open the output file, either with im_open(), or with it's
own system (nip2 has it's own open file thing to give progress feedback and
use disc for format conversion), and be responsible for deleting the temp
output file at some point.
*/
char *
im_system_image( IMAGE *im,
const char *in_format, const char *out_format, const char *cmd_format,
char **log )
{
char *in_name;
char *out_name;
if( log )
*log = NULL;
in_name = im__temp_name( in_format );
out_name = im__temp_name( in_format );
if( !in_name ||
!out_name ||
system_image( im, in_name, out_name, cmd_format, log ) ) {
g_free( in_name );
g_free( out_name );
return( NULL );
}
g_free( in_name );
return( out_name );
}

View File

@ -111,6 +111,9 @@ int im_subsample( IMAGE *in, IMAGE *out, int x, int y );
int im_zoom( IMAGE *in, IMAGE *out, int x, int y );
int im_system( IMAGE *im, const char *cmd, char **out );
char *im_system_image( IMAGE *im,
const char *in_format, const char *out_format, const char *cmd_format,
char **log );
#ifdef __cplusplus
}

View File

@ -248,10 +248,13 @@ const char *vips__token_need( const char *buffer, VipsToken need_token,
int im_existsf( const char *name, ... )
__attribute__((format(printf, 1, 2)));
FILE *im_popenf( const char *fmt, const char *mode, ... )
__attribute__((format(printf, 1, 3)));
int im_ispoweroftwo( int p );
int im_isvips( const char *filename );
int im_amiMSBfirst( void );
char *im__temp_name( const char *format );
IMAGE *im__open_temp( void );
int im_bits_of_fmt( VipsBandFmt fmt );

View File

@ -82,6 +82,7 @@ extern "C" {
#endif /*__cplusplus*/
#include <glib.h>
#include <glib/gstdio.h>
#include <gmodule.h>
#include <glib-object.h>

View File

@ -28,8 +28,8 @@
*/
/*
#define DEBUG
*/
#define DEBUG
#ifdef HAVE_CONFIG_H
#include <config.h>
@ -860,7 +860,7 @@ im__file_read( FILE *fp, const char *name, unsigned int *length_out )
} while( !feof( fp ) );
#ifdef DEBUG
printf( "read %d bytes from unseekable stream\n", len );
printf( "read %ld bytes from unseekable stream\n", len );
#endif /*DEBUG*/
}
else {
@ -1413,6 +1413,36 @@ im_existsf( const char *name, ... )
return( 0 );
}
#ifdef OS_WIN32
#define popen(b,m) _popen(b,m)
#define pclose(f) _pclose(f)
#endif /*OS_WIN32*/
/* Do popen(), with printf-style args.
*/
FILE *
im_popenf( const char *fmt, const char *mode, ... )
{
va_list args;
char buf[4096];
FILE *fp;
va_start( args, mode );
(void) im_vsnprintf( buf, 4096, fmt, args );
va_end( args );
#ifdef DEBUG
printf( "im_popenf: running: %s\n", buf );
#endif /*DEBUG*/
if( !(fp = popen( buf, mode )) ) {
im_error( "popenf", "%s", strerror( errno ) );
return( NULL );
}
return( fp );
}
/* True if an int is a power of two ... 1, 2, 4, 8, 16, 32, etc. Do with just
* integer arithmetic for portability. A previous Nicos version using doubles
* and log/log failed on x86 with rounding problems. Return 0 for not
@ -1478,30 +1508,55 @@ im_amiMSBfirst( void )
return( 1 );
}
/* Make a temporary file name. The format parameter is something like "%s.jpg"
* and will be expanded to something like "/tmp/vips-12-34587.jpg".
*
* You need to free the result. A real file will also be created, though we
* delete it for you.
*/
char *
im__temp_name( const char *format )
{
static int serial = 1;
const char *tmpd;
char file[FILENAME_MAX];
char file2[FILENAME_MAX];
char *name;
int fd;
if( !(tmpd = g_getenv( "TMPDIR" )) )
tmpd = "/tmp";
im_snprintf( file, FILENAME_MAX, "vips-%d-XXXXXX", serial++ );
im_snprintf( file2, FILENAME_MAX, format, file );
name = g_build_filename( tmpd, file2, NULL );
if( (fd = g_mkstemp( name )) == -1 ) {
im_error( "tempfile",
_( "unable to make temporary file %s" ), name );
g_free( name );
return( NULL );
}
close( fd );
g_unlink( name );
return( name );
}
/* Make a disc IMAGE which will be automatically unlinked on im_close().
*/
IMAGE *
im__open_temp( void )
{
const char *tmpd;
char *name;
int fd;
IMAGE *disc;
if( !(tmpd = g_getenv( "TMPDIR" )) )
tmpd = "/tmp";
name = g_build_filename( tmpd, "vips_XXXXXX.v", NULL );
if( (fd = g_mkstemp( name )) == -1 ) {
im_error( "tempfile",
_( "unable to make temp file %s" ), name );
g_free( name );
if( !(name = im__temp_name( "%s.v" )) )
return( NULL );
}
close( fd );
if( !(disc = im_open( name, "w" )) ) {
unlink( name );
g_free( name );
return( NULL );
}
@ -1510,7 +1565,7 @@ im__open_temp( void )
if( im_add_close_callback( disc,
(im_callback_fn) unlink, disc->filename, NULL ) ) {
im_close( disc );
unlink( name );
g_unlink( name );
}
return( disc );