libvips/swig/vipsCC/VImage.i
John Cupitt b51faee8ca support many-returns ops in Python
add various %apply rules to move values returned via args into the result
2012-02-06 14:54:54 +00:00

381 lines
11 KiB
OpenEdge ABL

/* SWIG interface file for vipsCC7
*
* 5/9/07
* - use g_option_context_set_ignore_unknown_options() so we don't fail
* on unrecognied -args (thanks Simon)
* 3/8/08
* - add .tobuffer() / .frombuffer (), .tostring (), .fromstring ()
* methods
* - add PIL_mode_from_vips () and vips_from_PIL_mode () utility
* functions
* 6/11/09
* - arg, std::vector<vips::VImage> was missing the "vips::"
*/
%module VImage
%{
#include <vips/vipscpp.h>
/* We need the C API too for the args init and some of the
* frombuffer/tobuffer stuff.
*/
#include <vips/vips.h>
%}
/* Need to override assignment to get refcounting working.
*/
%rename(__assign__) vips::VImage::operator=;
%include "std_list.i"
%include "std_complex.i"
%include "std_vector.i"
%include "std_except.i"
%include "std_string.i"
%include "cstring.i"
%include "typemaps.i"
%import "VError.i"
%import "VMask.i"
%import "VDisplay.i"
namespace std {
%template(IntVector) vector<int>;
%template(DoubleVector) vector<double>;
%template(ImageVector) vector<vips::VImage>;
}
/* To get image data to and from VImage (eg. when interfacing with PIL) we
* need to be able to import and export Python buffer() objects. Add new
* methods to construct from and return pointer/length pairs, then wrap them
* ourselves with a couple of typemaps.
*/
%{
struct VBuffer {
void *data;
size_t size;
};
%}
%typemap (out) VBuffer {
$result = PyBuffer_FromMemory ($1.data, $1.size);
}
%typemap (in) VBuffer {
const char *buffer;
Py_ssize_t buffer_len;
if (PyObject_AsCharBuffer ($input, &buffer, &buffer_len) == -1) {
PyErr_SetString (PyExc_TypeError,"Type error. Unable to get char pointer from buffer");
return NULL;
}
$1.data = (void *) buffer;
$1.size = buffer_len;
}
/* Functions which return extra values though their parameters need special
* typemaps.
*/
// double maxpos_avg( double& maxpos_avg_y, double& maxpos_avg_out )
%apply double *OUTPUT { double & maxpos_avg_y };
%apply double *OUTPUT { double & maxpos_avg_out };
// VImage system_image( char* system_image_in_format, char* system_image_out_format, char* system_image_command, char*& system_image_log )
%cstring_output_allocate(char **system_image_log, g_free(*$1));
// VImage segment( int& segment_segments )
%apply int *OUTPUT { int & segment_segments };
// VImage project( VImage& project_vout ) throw( VError );
// nope ... not sure how to handle this one
//%apply VImage *OUTPUT { VImage & project_vout };
// VImage label_regions( int& label_regions_segments )
%apply int *OUTPUT { int & label_regions_segments };
// double correl( VImage correl_sec, int correl_xref, int correl_yref, int correl_xsec, int correl_ysec, int correl_hwindowsize, int correl_hsearchsize, int& correl_x, int& correl_y )
%apply int *OUTPUT { int & correl_x };
%apply int *OUTPUT { int & correl_y };
// int _find_lroverlap( VImage _find_lroverlap_sec, int _find_lroverlap_bandno, int _find_lroverlap_xr, int _find_lroverlap_yr, int _find_lroverlap_xs, int _find_lroverlap_ys, int _find_lroverlap_halfcorrelation, int _find_lroverlap_halfarea, int& _find_lroverlap_dy0, double& _find_lroverlap_scale1, double& _find_lroverlap_angle1, double& _find_lroverlap_dx1, double& _find_lroverlap_dy1 )
%apply int *OUTPUT { int & _find_lroverlap_dy0 };
%apply double *OUTPUT { double & _find_lroverlap_scale1 };
%apply double *OUTPUT { double & _find_lroverlap_angle1 };
%apply double *OUTPUT { double & _find_lroverlap_dx1 };
%apply double *OUTPUT { double & _find_lroverlap_dy1 };
// int _find_tboverlap( VImage _find_tboverlap_sec, int _find_tboverlap_bandno, int _find_tboverlap_xr, int _find_tboverlap_yr, int _find_tboverlap_xs, int _find_tboverlap_ys, int _find_tboverlap_halfcorrelation, int _find_tboverlap_halfarea, int& _find_tboverlap_dy0, double& _find_tboverlap_scale1, double& _find_tboverlap_angle1, double& _find_tboverlap_dx1, double& _find_tboverlap_dy1 )
%apply int *OUTPUT { int & _find_tboverlap_dy0 };
%apply double *OUTPUT { double & _find_tboverlap_scale1 };
%apply double *OUTPUT { double & _find_tboverlap_angle1 };
%apply double *OUTPUT { double & _find_tboverlap_dx1 };
%apply double *OUTPUT { double & _find_tboverlap_dy1 };
// double maxpos_subpel( double& maxpos_subpel_y )
%apply double *OUTPUT { double & maxpos_subpel_y };
/* Need the expanded VImage.h in this directory, rather than the usual
* vips/VImage.h. SWIG b0rks on #include inside class definitions.
*/
%include VImage.h
%extend vips::VImage {
public:
VBuffer tobuffer () throw (VError)
{
VBuffer buffer;
buffer.data = $self->data ();
buffer.size = (size_t) $self->Xsize () * $self->Ysize () *
IM_IMAGE_SIZEOF_PEL ($self->image ());
return buffer;
}
static VImage frombuffer (VBuffer buffer, int width, int height,
int bands, TBandFmt format) throw (VError)
{
return VImage (buffer.data, width, height, bands, format);
}
%cstring_output_allocate_size (char **buffer, int *buffer_len, im_free (*$1))
void tostring (char **buffer, int *buffer_len) throw (VError)
{
void *vips_memory;
/* Eval the vips image first. This may throw an exception and we want to
* make sure we do this before we try to malloc() space for the copy.
*/
vips_memory = $self->data ();
/* We have to copy the image data to make a string that Python can
* manage. Use frombuffer() / tobuffer () if you want to avoid the copy
* and manage memory lifetime yourself.
*/
*buffer_len = (size_t) $self->Xsize () * $self->Ysize () *
IM_IMAGE_SIZEOF_PEL ($self->image ());
if (!(*buffer = (char *) im_malloc (NULL, *buffer_len)))
verror ("Unable to allocate memory for image copy.");
memcpy (*buffer, vips_memory, *buffer_len);
}
static VImage fromstring (std::string buffer, int width, int height,
int bands, TBandFmt format) throw (VError)
{
void *vips_memory;
VImage result;
/* We have to copy the string, then add a callback to the VImage to free
* it when we free the VImage. Use frombuffer() / tobuffer () if you want
* to avoid the copy and manage memory lifetime yourself.
*/
if (!(vips_memory = im_malloc (NULL, buffer.length ())))
verror ("Unable to allocate memory for image copy.");
/* We have to use .c_str () since the string may not be contiguous.
*/
memcpy (vips_memory, buffer.c_str (), buffer.length ());
result = VImage (vips_memory, width, height, bands, format);
if (im_add_close_callback (result.image (),
(im_callback_fn) im_free, vips_memory, NULL))
verror ();
return result;
}
}
%pythoncode %{
# try to guess a PIL mode string from a VIPS image
def PIL_mode_from_vips (vim):
if vim.Bands () == 3 and vim.BandFmt () == VImage.FMTUCHAR:
return 'RGB'
elif vim.Bands () == 4 and vim.BandFmt () == VImage.FMTUCHAR and vim.Type == VImage.VImage.RGB:
return 'RGBA'
elif vim.Bands () == 4 and vim.BandFmt () == VImage.FMTUCHAR and vim.Type == VImage.CMYK:
return 'CMYK'
elif vim.Bands () == 1 and vim.BandFmt () == VImage.FMTUCHAR:
return 'L'
elif vim.Bands () == 1 and vim.BandFmt () == VImage.FMTINT:
return 'I'
elif vim.Bands () == 1 and vim.BandFmt () == VImage.FMTFLOAT:
return 'F'
elif vim.Bands () == 2 and vim.BandFmt () == VImage.FMTUCHAR:
return 'LA'
else:
raise ValueError ('unsupported vips -> pil image')
# return vips (bands, format, type) for a PIL mode
def vips_from_PIL_mode (mode):
if mode == 'RGB':
return (3, VImage.FMTUCHAR, VImage.RGB)
elif mode == 'RGBA':
return (4, VImage.FMTUCHAR, VImage.RGB)
elif mode == 'CMYK':
return (4, VImage.FMTUCHAR, VImage.CMYK)
elif mode == 'L':
return (1, VImage.FMTUCHAR, VImage.B_W)
elif mode == 'I':
return (1, VImage.FMTINT, VImage.B_W)
elif mode == 'F':
return (1, VImage.FMTFLOAT, VImage.B_W)
elif mode == 'LA':
return (2, VImage.FMTUCHAR, VImage.B_W)
else:
raise ValueError ('unsupported pil -> vips image')
%}
/* Helper code for vips_init().
*/
%{
/* Turn on to print args.
#define DEBUG
*/
/* Command-line args during parse.
*/
typedef struct _Args {
/* The n strings we alloc when we get from Python.
*/
int n;
char **str;
/* argc/argv as processed by us.
*/
int argc;
char **argv;
} Args;
#ifdef DEBUG
static void
args_print (Args *args)
{
int i;
printf ("args_print: argc = %d\n", args->argc);
// +1 so we print the trailing NULL too
for (i = 0; i < args->argc + 1; i++)
printf ("\t%2d)\t%s\n", i, args->argv[i]);
}
#endif /*DEBUG*/
static void
args_free (Args *args)
{
int i;
for (i = 0; i < args->n; i++)
IM_FREE (args->str[i]);
args->n = 0;
args->argc = 0;
IM_FREE (args->str);
IM_FREE (args->argv);
IM_FREE (args);
}
/* Get argv/argc from python.
*/
static Args *
args_new (void)
{
Args *args;
PyObject *av;
int i;
int n;
args = g_new (Args, 1);
args->n = 0;
args->str = NULL;
args->argc = 0;
args->argv = NULL;
if (!(av = PySys_GetObject ((char *) "argv")))
return (args);
if (!PyList_Check (av)) {
PyErr_Warn (PyExc_Warning, "ignoring sys.argv: "
"it must be a list of strings");
return args;
}
n = PyList_Size (av);
args->str = g_new (char *, n);
for (i = 0; i < n; i++)
args->str[i] = g_strdup (PyString_AsString (PyList_GetItem (av, i)));
args->n = n;
/* +1 for NULL termination.
*/
args->argc = n;
args->argv = g_new (char *, n + 1);
for (i = 0; i < n; i++)
args->argv[i] = args->str[i];
args->argv[i] = NULL;
return args;
}
static void
vips_fatal (const char *msg)
{
char buf[256];
im_snprintf (buf, 256, "%s\n%s", msg, im_error_buffer());
im_error_clear ();
Py_FatalError (buf);
}
%}
%init %{
{
Args *args;
args = args_new ();
#ifdef DEBUG
printf ("on startup:\n");
args_print (args);
#endif /*DEBUG*/
if (im_init_world (args->argv[0])) {
args_free (args);
vips_fatal ("can't initialise module vips");
}
/* Now parse any GOptions.
*/
GError *error = NULL;
GOptionContext *context;
context = g_option_context_new ("- vips");
g_option_context_add_group (context, im_get_option_group());
g_option_context_set_ignore_unknown_options (context, TRUE);
if (!g_option_context_parse (context,
&args->argc, &args->argv, &error)) {
g_option_context_free (context);
args_free (args);
im_error ("vipsmodule", "%s", error->message);
g_error_free (error);
vips_fatal ("can't initialise module vips");
}
g_option_context_free (context);
#ifdef DEBUG
printf ("after parse:\n");
args_print (args);
#endif /*DEBUG*/
// Write (possibly) modified argc/argv back again.
if (args->argv)
PySys_SetArgv (args->argc, args->argv);
args_free (args);
}
%}