/* 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., 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)

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; 

	result = pclose( fp );

	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.
 *
 * 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: 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 );

		return( NULL );
	}
	im_close( in_image );

	if( !(out = im_open( out_name, "r" )) ) {
		g_free( out_name );

		return( NULL );
	}
	if( im_add_postclose_callback( out, 
		(im_callback_fn) unlink, out->filename, NULL ) ) {
		g_free( out_name );
		im_close( out );
		g_unlink( out_name );

		return( NULL );
	}
	g_free( out_name );

	return( out );
}
