From c4a3e9a1a01a1be2b650cf87c3c8dfe4f17bcc86 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Mon, 15 Sep 2014 14:47:34 +0100 Subject: [PATCH] add VIPS_ARGUMENT_MODIFY a flag for arguments meaning the operator will modify an input the python binding uses this to take a copy of the arg before calling --- ChangeLog | 2 ++ libvips/draw/draw.c | 2 +- libvips/include/vips/object.h | 3 ++- libvips/iofuncs/enumtypes.c | 1 + libvips/iofuncs/object.c | 4 ++++ python/vips8/vips.py | 23 +++++++++++++++-------- 6 files changed, 25 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 210d03bc..12b0b90e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,8 @@ - return of vips_init(), but just for bindings - revised type.c to make it more binding-friendly - add @background arg to save: the colour to flatten against +- add VIPS_ARGUMENT_MODIFY flag ... used for draw_circle etc, meaning an op + which modifies its argument 8/9/14 started 7.40.9 - support jfif resunit "none" diff --git a/libvips/draw/draw.c b/libvips/draw/draw.c index de6c0a72..08221988 100644 --- a/libvips/draw/draw.c +++ b/libvips/draw/draw.c @@ -115,7 +115,7 @@ vips_draw_class_init( VipsDrawClass *class ) VIPS_ARG_IMAGE( class, "image", 1, _( "Image" ), _( "Image to draw on" ), - VIPS_ARGUMENT_REQUIRED_INPUT, + VIPS_ARGUMENT_REQUIRED_INPUT | VIPS_ARGUMENT_MODIFY, G_STRUCT_OFFSET( VipsDraw, image ) ); } diff --git a/libvips/include/vips/object.h b/libvips/include/vips/object.h index 7c0487d5..6a586c3e 100644 --- a/libvips/include/vips/object.h +++ b/libvips/include/vips/object.h @@ -63,7 +63,8 @@ typedef enum /*< flags >*/ { VIPS_ARGUMENT_SET_ALWAYS = 8, VIPS_ARGUMENT_INPUT = 16, VIPS_ARGUMENT_OUTPUT = 32, - VIPS_ARGUMENT_DEPRECATED = 64 + VIPS_ARGUMENT_DEPRECATED = 64, + VIPS_ARGUMENT_MODIFY = 128 } VipsArgumentFlags; /* Useful flag combinations. User-visible ones are: diff --git a/libvips/iofuncs/enumtypes.c b/libvips/iofuncs/enumtypes.c index 01bf9fff..ede5e081 100644 --- a/libvips/iofuncs/enumtypes.c +++ b/libvips/iofuncs/enumtypes.c @@ -743,6 +743,7 @@ vips_argument_flags_get_type( void ) {VIPS_ARGUMENT_INPUT, "VIPS_ARGUMENT_INPUT", "input"}, {VIPS_ARGUMENT_OUTPUT, "VIPS_ARGUMENT_OUTPUT", "output"}, {VIPS_ARGUMENT_DEPRECATED, "VIPS_ARGUMENT_DEPRECATED", "deprecated"}, + {VIPS_ARGUMENT_MODIFY, "VIPS_ARGUMENT_MODIFY", "modify"}, {0, NULL, NULL} }; diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index cc8cd72f..30664050 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -169,6 +169,7 @@ * @VIPS_ARGUMENT_INPUT: is an input argument (one we depend on) * @VIPS_ARGUMENT_OUTPUT: is an output argument (depends on us) * @VIPS_ARGUMENT_DEPRECATED: just there for back-compat, hide + * @VIPS_ARGUMENT_MODIFY: the input argument will be modified * * Flags we associate with each object argument. * @@ -186,6 +187,9 @@ * looked for if required, are not checked for "have-been-set". You can * deprecate a required argument, but you must obviously add a new required * argument if you do. + * + * Input args with @VIPS_ARGUMENT_MODIFY will be modified by the operation. + * This is used for things like the in-place drawing operations. */ /* Our signals. diff --git a/python/vips8/vips.py b/python/vips8/vips.py index b1b8de4e..6daf7a3b 100644 --- a/python/vips8/vips.py +++ b/python/vips8/vips.py @@ -79,6 +79,11 @@ class Argument: if not isinstance(value, Vips.Blob): value = Vips.Blob.new(None, value) + # MODIFY input images need to be copied before assigning them + if self.flags & Vips.ArgumentFlags.MODIFY: + print 'taking copy of MODIFY image arg' + value = value.copy() + logging.debug('assigning %s' % self.prop.value_type) self.op.props.__setattr__(self.name, value) @@ -171,16 +176,18 @@ def _call_base(name, required, optional, self = None, option_string = None): args = [Argument(op2, x) for x in op2.props] args.sort(lambda a, b: a.priority - b.priority) - # find all required output args - # we can't check assigned here (since we captured the value before the call) - # but the getattr will test that for us anyway - required_output = [x for x in args if x.flags & enm.OUTPUT and - x.flags & enm.REQUIRED] - # gather output args out = [] - for x in required_output: - out.append(x.get_value()) + + for x in args: + # required output arg + if x.flags & enm.OUTPUT and x.flags & enm.REQUIRED: + out.append(x.get_value()) + + # modified input arg ... this will get the result of the copy() we + # did above + if x.flags & enm.INPUT and x.flags & enm.MODIFY: + out.append(x.get_value()) # find all optional output args optional_output = [x.name for x in args if x.flags & enm.OUTPUT and