diff --git a/ChangeLog b/ChangeLog index 06716c46..91c1741b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,6 +22,9 @@ - added vips_image_write(), old one becomes vips_image_write_to_file() - jpeg read/write copies over XMP data - handle offset correctly in separable convolutions (thanks Nicolas) +- macros for class arg boilerplate +- class arg order set by new 'priority' param +- VipsExtend enum added 12/9/11 started 7.26.4 - fallback vips_init() diff --git a/TODO b/TODO index e006ab92..e4cd3136 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,55 @@ +- embed args are in the wrong order + + $ vips embed + vips_embed_class_init + VipsEmbed (embed), embed an image in a larger image + embed input type x y width height out + where: + input :: VipsImage (input) + type :: gint (input) + x :: gint (input) + y :: gint (input) + width :: gint (input) + height :: gint (input) + out :: VipsImage (output) + + how can we fix this? + + need to give an extra arg to vips_object_class_install_argument() to + specify 'argument priority' ... show args in priority order + + + +- try some macros for arg specification + + pspec = g_param_spec_int( "y", "Y", + _( "Top edge of input in output" ), + 0, 1000000, 0, + G_PARAM_READWRITE ); + g_object_class_install_property( gobject_class, PROP_Y, pspec ); + vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsEmbed, y ) ); + + could become + + VIPS_ARG_INT( class, "y", "Y", + _( "Top edge of input in output" ), + 0, 1000000, 0, + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsEmbed, y ) ); + + could get rid of PROP_ enums as well + + + doing binary.c next + + + +- make 'type' field to embed an enum? + + + - vips_object_set_argument_from_string() needs more arg types must be some way to make this more automatic diff --git a/libvips/arithmetic/arithmetic.c b/libvips/arithmetic/arithmetic.c index bed9992f..2ccb7712 100644 --- a/libvips/arithmetic/arithmetic.c +++ b/libvips/arithmetic/arithmetic.c @@ -53,15 +53,6 @@ #include "arithmetic.h" -/* Properties. - */ -enum { - PROP_OUTPUT = 1, - PROP_BOOLTEST = 2, - PROP_IMTEST = 3, - PROP_LAST -}; - G_DEFINE_ABSTRACT_TYPE( VipsArithmetic, vips_arithmetic, VIPS_TYPE_OPERATION ); static int @@ -96,8 +87,6 @@ vips_arithmetic_class_init( VipsArithmeticClass *class ) GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); - GParamSpec *pspec; - gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; @@ -105,33 +94,22 @@ vips_arithmetic_class_init( VipsArithmeticClass *class ) vobject_class->description = _( "arithmetic operations" ); vobject_class->build = vips_arithmetic_build; - pspec = g_param_spec_object( "out", "Output", + VIPS_ARG_IMAGE( class, "out", 1, + _( "Output" ), _( "Output image" ), - VIPS_TYPE_IMAGE, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, - PROP_OUTPUT, pspec ); - vips_object_class_install_argument( vobject_class, pspec, VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET( VipsArithmetic, output ) ); - pspec = g_param_spec_boolean( "booltest", "Bool test", + VIPS_ARG_BOOL( class, "booltest", 2, + _( "Bool test" ), _( "Test optional boolean argument" ), - FALSE, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, - PROP_BOOLTEST, pspec ); - vips_object_class_install_argument( vobject_class, pspec, VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsArithmetic, booltest ) ); + G_STRUCT_OFFSET( VipsArithmetic, booltest ), + FALSE ); - pspec = g_param_spec_object( "imtest", "Image test", + VIPS_ARG_IMAGE( class, "imtest", 3, + _( "Image test" ), _( "Test optional image argument" ), - VIPS_TYPE_IMAGE, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, - PROP_IMTEST, pspec ); - vips_object_class_install_argument( vobject_class, pspec, VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET( VipsArithmetic, imtest ) ); } diff --git a/libvips/arithmetic/avg.c b/libvips/arithmetic/avg.c index beddd718..c860839b 100644 --- a/libvips/arithmetic/avg.c +++ b/libvips/arithmetic/avg.c @@ -86,13 +86,6 @@ * See also: im_stats(), im_bandmean(), im_deviate(), im_rank() */ -/* Properties. - */ -enum { - PROP_OUTPUT = 1, - PROP_LAST -}; - typedef struct _VipsAvg { VipsStatistic parent_instance; @@ -228,8 +221,6 @@ vips_avg_class_init( VipsAvgClass *class ) VipsObjectClass *object_class = (VipsObjectClass *) class; VipsStatisticClass *sclass = VIPS_STATISTIC_CLASS( class ); - GParamSpec *pspec; - gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; @@ -241,17 +232,12 @@ vips_avg_class_init( VipsAvgClass *class ) sclass->scan = vips_avg_scan; sclass->stop = vips_avg_stop; - pspec = g_param_spec_double( "out", "Output", + VIPS_ARG_DOUBLE( class, "out", 2, + _( "Output" ), _( "Output value" ), - -G_MAXDOUBLE, - G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, - PROP_OUTPUT, pspec ); - vips_object_class_install_argument( object_class, pspec, - VIPS_ARGUMENT_REQUIRED_OUTPUT | VIPS_ARGUMENT_APPEND, - G_STRUCT_OFFSET( VipsAvg, avg ) ); + VIPS_ARGUMENT_REQUIRED_OUTPUT, + G_STRUCT_OFFSET( VipsAvg, avg ), + -G_MAXDOUBLE, G_MAXDOUBLE, 0.0 ); } static void diff --git a/libvips/arithmetic/binary.c b/libvips/arithmetic/binary.c index dcd1b058..5cddaaa8 100644 --- a/libvips/arithmetic/binary.c +++ b/libvips/arithmetic/binary.c @@ -50,14 +50,6 @@ #include "arithmetic.h" #include "binary.h" -/* Properties. - */ -enum { - PROP_LEFT = 1, - PROP_RIGHT, - PROP_LAST -}; - G_DEFINE_ABSTRACT_TYPE( VipsBinary, vips_binary, VIPS_TYPE_ARITHMETIC ); /* Save a bit of typing. @@ -348,8 +340,6 @@ vips_binary_class_init( VipsBinaryClass *class ) GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); - GParamSpec *pspec; - gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; @@ -359,23 +349,15 @@ vips_binary_class_init( VipsBinaryClass *class ) /* Create properties. */ - pspec = g_param_spec_object( "right", - "Right", "Right-hand image argument", - VIPS_TYPE_IMAGE, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, - PROP_RIGHT, pspec ); - vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARG_IMAGE( class, "right", 1, + _( "Right" ), + _( "Right-hand image argument" ), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET( VipsBinary, right ) ); - pspec = g_param_spec_object( "left", - "Left", "Left-hand image argument", - VIPS_TYPE_IMAGE, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, - PROP_LEFT, pspec ); - vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARG_IMAGE( class, "left", 2, + _( "Left" ), + _( "Left-hand image argument" ), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET( VipsBinary, left ) ); } diff --git a/libvips/arithmetic/min.c b/libvips/arithmetic/min.c index 7fef11f4..9fec8012 100644 --- a/libvips/arithmetic/min.c +++ b/libvips/arithmetic/min.c @@ -83,15 +83,6 @@ * See also: #VipsAvg, im_stats(), im_bandmean(), im_deviate(), im_rank() */ -/* Properties. - */ -enum { - PROP_OUTPUT = 1, - PROP_X, /* Position of minimum */ - PROP_Y, - PROP_LAST -}; - typedef struct _VipsMin { VipsStatistic parent_instance; @@ -291,8 +282,6 @@ vips_min_class_init( VipsMinClass *class ) VipsObjectClass *object_class = (VipsObjectClass *) class; VipsStatisticClass *sclass = VIPS_STATISTIC_CLASS( class ); - GParamSpec *pspec; - gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; @@ -304,37 +293,26 @@ vips_min_class_init( VipsMinClass *class ) sclass->scan = vips_min_scan; sclass->stop = vips_min_stop; - pspec = g_param_spec_double( "out", "Output", + VIPS_ARG_DOUBLE( class, "out", 1, + _( "Output" ), _( "Output value" ), - -G_MAXDOUBLE, - G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, - PROP_OUTPUT, pspec ); - vips_object_class_install_argument( object_class, pspec, - VIPS_ARGUMENT_REQUIRED_OUTPUT | VIPS_ARGUMENT_APPEND, - G_STRUCT_OFFSET( VipsMin, min ) ); + VIPS_ARGUMENT_REQUIRED_OUTPUT, + G_STRUCT_OFFSET( VipsMin, min ), + -G_MAXDOUBLE, G_MAXDOUBLE, 0.0 ); - pspec = g_param_spec_int( "x", "x", + VIPS_ARG_INT( class, "x", 2, + _( "x" ), _( "Horizontal position of minimum" ), - 0, 1000000, 0, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, - PROP_X, pspec ); - vips_object_class_install_argument( object_class, pspec, VIPS_ARGUMENT_OPTIONAL_OUTPUT, - G_STRUCT_OFFSET( VipsMin, x ) ); + G_STRUCT_OFFSET( VipsMin, x ), + 0, 1000000, 0 ); - pspec = g_param_spec_int( "y", "y", + VIPS_ARG_INT( class, "y", 2, + _( "y" ), _( "Vertical position of minimum" ), - 0, 1000000, 0, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, - PROP_Y, pspec ); - vips_object_class_install_argument( object_class, pspec, VIPS_ARGUMENT_OPTIONAL_OUTPUT, - G_STRUCT_OFFSET( VipsMin, y ) ); + G_STRUCT_OFFSET( VipsMin, y ), + 0, 1000000, 0 ); } static void diff --git a/libvips/arithmetic/statistic.c b/libvips/arithmetic/statistic.c index 6acb6bcd..d0e77ef4 100644 --- a/libvips/arithmetic/statistic.c +++ b/libvips/arithmetic/statistic.c @@ -52,13 +52,6 @@ #include "statistic.h" -/* Properties. - */ -enum { - PROP_INPUT = 1, - PROP_LAST -}; - G_DEFINE_ABSTRACT_TYPE( VipsStatistic, vips_statistic, VIPS_TYPE_OPERATION ); static void * @@ -147,8 +140,6 @@ vips_statistic_class_init( VipsStatisticClass *class ) GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); - GParamSpec *pspec; - gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; @@ -156,14 +147,10 @@ vips_statistic_class_init( VipsStatisticClass *class ) vobject_class->description = _( "VIPS statistic operations" ); vobject_class->build = vips_statistic_build; - pspec = g_param_spec_object( "in", "Input", + VIPS_ARG_IMAGE( class, "in", 1, + _( "Input" ), _( "Input image" ), - VIPS_TYPE_IMAGE, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, - PROP_INPUT, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_REQUIRED_INPUT, + VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET( VipsStatistic, input ) ); } diff --git a/libvips/conversion/Makefile.am b/libvips/conversion/Makefile.am index 37e537f5..1c4722c6 100644 --- a/libvips/conversion/Makefile.am +++ b/libvips/conversion/Makefile.am @@ -4,6 +4,7 @@ libconversion_la_SOURCES = \ conversion.c \ conversion.h \ copy.c \ + embed.c \ conver_dispatch.c \ im_black.c \ im_c2amph.c \ diff --git a/libvips/conversion/conversion.c b/libvips/conversion/conversion.c index 4c5e2d5f..0924d0fc 100644 --- a/libvips/conversion/conversion.c +++ b/libvips/conversion/conversion.c @@ -50,13 +50,6 @@ #include "conversion.h" -/* Properties. - */ -enum { - PROP_OUTPUT = 1, - PROP_LAST -}; - G_DEFINE_ABSTRACT_TYPE( VipsConversion, vips_conversion, VIPS_TYPE_OPERATION ); static int @@ -84,8 +77,6 @@ vips_conversion_class_init( VipsConversionClass *class ) GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); - GParamSpec *pspec; - gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; @@ -93,13 +84,9 @@ vips_conversion_class_init( VipsConversionClass *class ) vobject_class->description = _( "conversion operations" ); vobject_class->build = vips_conversion_build; - pspec = g_param_spec_object( "out", "Output", + VIPS_ARG_IMAGE( class, "out", 1, + _( "Output" ), _( "Output image" ), - VIPS_TYPE_IMAGE, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, - PROP_OUTPUT, pspec ); - vips_object_class_install_argument( vobject_class, pspec, VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET( VipsConversion, output ) ); } @@ -116,7 +103,9 @@ void vips_conversion_operation_init( void ) { extern GType vips_copy_get_type( void ); + extern GType vips_embed_get_type( void ); vips_copy_get_type(); + vips_embed_get_type(); } diff --git a/libvips/conversion/copy.c b/libvips/conversion/copy.c index fb13797b..5d9a3685 100644 --- a/libvips/conversion/copy.c +++ b/libvips/conversion/copy.c @@ -74,8 +74,8 @@ */ /* - */ #define VIPS_DEBUG + */ #ifdef HAVE_CONFIG_H #include @@ -108,24 +108,6 @@ * Returns: 0 on success, -1 on error. */ -/* Properties. - */ -enum { - PROP_INPUT = 1, - PROP_SWAP, - PROP_WIDTH, - PROP_HEIGHT, - PROP_BANDS, - PROP_FORMAT, - PROP_CODING, - PROP_INTERPRETATION, - PROP_XRES, - PROP_YRES, - PROP_XOFFSET, - PROP_YOFFSET, - PROP_LAST -}; - typedef struct _VipsCopy { VipsConversion parent_instance; @@ -344,8 +326,6 @@ vips_copy_class_init( VipsCopyClass *class ) GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); - GParamSpec *pspec; - VIPS_DEBUG_MSG( "vips_copy_class_init\n" ); gobject_class->set_property = vips_object_set_property; @@ -355,116 +335,88 @@ vips_copy_class_init( VipsCopyClass *class ) vobject_class->description = _( "copy an image" ); vobject_class->build = vips_copy_build; - pspec = g_param_spec_object( "input", - "Input", "Input image argument", - VIPS_TYPE_IMAGE, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, - PROP_INPUT, pspec ); - vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARG_IMAGE( class, "in", 1, + _( "Input" ), + _( "Input image" ), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET( VipsCopy, input ) ); - pspec = g_param_spec_boolean( "swap", "Swap", + VIPS_ARG_BOOL( class, "swap", 2, + _( "Swap" ), _( "Swap bytes in image between little and big-endian" ), - FALSE, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_SWAP, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsCopy, swap ) ); + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsCopy, swap ), + FALSE ); - pspec = g_param_spec_int( "width", "Width", + VIPS_ARG_INT( class, "width", 2, + _( "Width" ), _( "Image width in pixels" ), - 0, 1000000, 0, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_WIDTH, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsCopy, width ) ); + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsCopy, width ), + 0, 1000000, 0 ); - pspec = g_param_spec_int( "height", "Height", + VIPS_ARG_INT( class, "height", 3, + _( "Height" ), _( "Image height in pixels" ), - 0, 1000000, 0, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_HEIGHT, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsCopy, height ) ); + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsCopy, height ), + 0, 1000000, 0 ); - pspec = g_param_spec_int( "bands", "Bands", + VIPS_ARG_INT( class, "bands", 4, + _( "Bands" ), _( "Number of bands in image" ), - 0, 1000000, 0, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_BANDS, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsCopy, bands ) ); + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsCopy, bands ), + 0, 1000000, 0 ); - pspec = g_param_spec_enum( "format", "Format", + VIPS_ARG_ENUM( class, "format", 5, + _( "Format" ), _( "Pixel format in image" ), - VIPS_TYPE_BAND_FORMAT, VIPS_FORMAT_UCHAR, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_FORMAT, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsCopy, format ) ); + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsCopy, format ), + VIPS_TYPE_BAND_FORMAT, VIPS_FORMAT_UCHAR ); - pspec = g_param_spec_enum( "coding", "Coding", + VIPS_ARG_ENUM( class, "coding", 6, + _( "Coding" ), _( "Pixel coding" ), - VIPS_TYPE_CODING, VIPS_CODING_NONE, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_CODING, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsCopy, coding ) ); + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsCopy, coding ), + VIPS_TYPE_CODING, VIPS_CODING_NONE ); - pspec = g_param_spec_enum( "interpretation", "Interpretation", + VIPS_ARG_ENUM( class, "interpretation", 7, + _( "Interpretation" ), _( "Pixel interpretation" ), - VIPS_TYPE_INTERPRETATION, VIPS_INTERPRETATION_MULTIBAND, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, - PROP_INTERPRETATION, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsCopy, interpretation ) ); + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsCopy, interpretation ), + VIPS_TYPE_INTERPRETATION, VIPS_INTERPRETATION_MULTIBAND ); - pspec = g_param_spec_double( "xres", "XRes", + VIPS_ARG_DOUBLE( class, "xres", 8, + _( "Xres" ), _( "Horizontal resolution in pixels/mm" ), - 0, 1000000, 0, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_XRES, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsCopy, xres ) ); + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsCopy, xres ), + 0, 1000000, 0 ); - pspec = g_param_spec_double( "yres", "YRes", + VIPS_ARG_DOUBLE( class, "yres", 9, + _( "Yres" ), _( "Vertical resolution in pixels/mm" ), - 0, 1000000, 0, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_YRES, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsCopy, yres ) ); + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsCopy, yres ), + 0, 1000000, 0 ); - pspec = g_param_spec_int( "xoffset", "XOffset", + VIPS_ARG_INT( class, "xoffset", 10, + _( "Xoffset" ), _( "Horizontal offset of origin" ), - -10000000, 1000000, 0, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_XOFFSET, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsCopy, xoffset ) ); + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsCopy, xoffset ), + -1000000, 1000000, 0 ); - pspec = g_param_spec_int( "yoffset", "YOffset", + VIPS_ARG_INT( class, "yoffset", 11, + _( "Yoffset" ), _( "Vertical offset of origin" ), - -10000000, 1000000, 0, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_YOFFSET, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsCopy, yoffset ) ); - + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsCopy, yoffset ), + -1000000, 1000000, 0 ); } static void diff --git a/libvips/conversion/embed.c b/libvips/conversion/embed.c new file mode 100644 index 00000000..00431db0 --- /dev/null +++ b/libvips/conversion/embed.c @@ -0,0 +1,617 @@ +/* im_embed + * + * Author: J. Cupitt + * Written on: 21/2/95 + * Modified on: + * 6/4/04 + * - added extend pixels from edge mode + * - sets Xoffset / Yoffset to x / y + * 15/4/04 + * - added replicate and mirror modes + * 4/3/05 + * - added solid white mode + * 4/1/07 + * - degenerate to im_copy() for 0/0/w/h + * 1/8/07 + * - more general ... x and y can be negative + * 24/3/09 + * - added IM_CODING_RAD support + * 5/11/09 + * - gtkdoc + * 27/1/10 + * - use im_region_paint() + * - cleanups + * 15/10/11 + * - rewrite as a class + */ + +/* + + 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 + + */ + +/* + */ +#define VIPS_DEBUG + +#ifdef HAVE_CONFIG_H +#include +#endif /*HAVE_CONFIG_H*/ +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "conversion.h" + +/** + * VipsEmbed: + * @in: input image + * @out: output image + * @type: how to generate the edge pixels + * @x: place @in at this x position in @out + * @y: place @in at this y position in @out + * @width: @out should be this many pixels across + * @height: @out should be this many pixels down + * + * The opposite of im_extract(): embed an image within a larger image. @type + * controls what appears in the new pels, see #VipsExtend. + * + * See also: im_extract_area(), im_insert(). + * + * Returns: 0 on success, -1 on error. + */ + +typedef struct _VipsEmbed { + VipsConversion parent_instance; + + /* The input image. + */ + VipsImage *input; + + VipsExtend type; + int x; + int y; + int width; + int height; + + /* Geometry calculations. + */ + Rect rout; /* Whole output area */ + Rect rsub; /* Rect occupied by image */ + + /* The 8 border pieces. The 4 borders strictly up/down/left/right of + * the main image, and the 4 corner pieces. + */ + Rect border[8]; +} VipsEmbed; + +typedef VipsConversionClass VipsEmbedClass; + +G_DEFINE_TYPE( VipsEmbed, vips_embed, VIPS_TYPE_CONVERSION ); + +/* r is the bit we are trying to paint, guaranteed to be entirely within + * border area i. Set out to be the edge of the image we need to paint the + * pixels in r. + */ +static void +vips_embed_find_edge( VipsEmbed *embed, VipsRect *r, int i, VipsRect *out ) +{ + /* Expand the border by 1 pixel, intersect with the image area, and we + * get the edge. Usually too much though: eg. we could make the entire + * right edge. + */ + *out = embed->border[i]; + vips_rect_marginadjust( out, 1 ); + vips_rect_intersectrect( out, &embed->rsub, out ); + + /* Usually too much though: eg. we could make the entire + * right edge. If we're strictly up/down/left/right of the image, we + * can trim. + */ + if( i == 0 || i == 2 ) { + VipsRect extend; + + /* Above or below. + */ + extend = *r; + extend.top = 0; + extend.height = embed->height; + vips_rect_intersectrect( out, &extend, out ); + } + if( i == 1 || i == 3 ) { + VipsRect extend; + + /* Left or right. + */ + extend = *r; + extend.left = 0; + extend.width = embed->width; + vips_rect_intersectrect( out, &extend, out ); + } +} + +/* Copy a single pixel sideways into a line of pixels. + */ +static void +vips_embed_copy_pixel( VipsEmbed *embed, PEL *q, PEL *p, int n ) +{ + const int bs = VIPS_IMAGE_SIZEOF_PEL( embed->input ); + + int x, b; + + for( x = 0; x < n; x++ ) + for( b = 0; b < bs; b++ ) + *q++ = p[b]; +} + +/* Paint r of region or. It's a border area, lying entirely within + * embed->border[i]. p points to the top-left source pixel to fill with. + * plsk is the line stride. + */ +static void +vips_embed_paint_edge( VipsEmbed *embed, + VipsRegion *or, int i, VipsRect *r, PEL *p, int plsk ) +{ + const int bs = VIPS_IMAGE_SIZEOF_PEL( embed->input ); + + VipsRect todo; + PEL *q; + int y; + + /* Pixels left to paint. + */ + todo = *r; + + /* Corner pieces ... copy the single pixel to paint the top line of + * todo, then use the line copier below to paint the rest of it. + */ + if( i > 3 ) { + q = (PEL *) VIPS_REGION_ADDR( or, todo.left, todo.top ); + vips_embed_copy_pixel( embed, q, p, todo.width ); + + p = q; + todo.top += 1; + todo.height -= 1; + } + + if( i == 1 || i == 3 ) { + /* Vertical line of pixels to copy. + */ + for( y = 0; y < todo.height; y++ ) { + q = (PEL *) VIPS_REGION_ADDR( or, + todo.left, todo.top + y ); + vips_embed_copy_pixel( embed, q, p, todo.width ); + p += plsk; + } + } + else { + /* Horizontal line of pixels to copy. + */ + for( y = 0; y < todo.height; y++ ) { + q = (PEL *) VIPS_REGION_ADDR( or, + todo.left, todo.top + y ); + memcpy( q, p, bs * todo.width ); + } + } +} + +static int +vips_embed_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop ) +{ + VipsRegion *ir = (VipsRegion *) seq; + VipsEmbed *embed = (VipsEmbed *) b; + VipsRect *r = &or->valid; + + Rect ovl; + int i; + PEL *p; + int plsk; + + /* Entirely within the input image? Generate the subimage and copy + * pointers. + */ + if( vips_rect_includesrect( &embed->rsub, r ) ) { + VipsRect need; + + need = *r; + need.left -= embed->x; + need.top -= embed->y; + if( vips_region_prepare( ir, &need ) || + vips_region_region( or, ir, r, need.left, need.top ) ) + return( -1 ); + + return( 0 ); + } + + /* Does any of the input image appear in the area we have been asked + * to make? Paste it in. + */ + vips_rect_intersectrect( r, &embed->rsub, &ovl ); + if( !vips_rect_isempty( &ovl ) ) { + /* Paint the bits coming from the input image. + */ + ovl.left -= embed->x; + ovl.top -= embed->y; + if( vips_region_prepare_to( ir, or, &ovl, + ovl.left + embed->x, ovl.top + embed->y ) ) + return( -1 ); + ovl.left += embed->x; + ovl.top += embed->y; + } + + switch( embed->type ) { + case 0: + case 4: + /* Paint the borders a solid value. + */ + for( i = 0; i < 8; i++ ) + vips_region_paint( or, &embed->border[i], + embed->type == 0 ? 0 : 255 ); + break; + + case 1: + /* Extend the borders. + */ + for( i = 0; i < 8; i++ ) { + VipsRect todo; + VipsRect edge; + + vips_rect_intersectrect( r, &embed->border[i], &todo ); + if( !vips_rect_isempty( &todo ) ) { + vips_embed_find_edge( embed, &todo, i, &edge ); + + /* Did we paint any of the input image? If we + * did, we can fetch the edge pixels from + * that. + */ + if( !vips_rect_isempty( &ovl ) ) { + p = (PEL *) VIPS_REGION_ADDR( or, + edge.left, edge.top ); + plsk = VIPS_REGION_LSKIP( or ); + } + else { + /* No pixels painted ... fetch + * directly from the input image. + */ + edge.left -= embed->x; + edge.top -= embed->y; + if( vips_region_prepare( ir, &edge ) ) + return( -1 ); + p = (PEL *) VIPS_REGION_ADDR( ir, + edge.left, edge.top ); + plsk = VIPS_REGION_LSKIP( ir ); + } + + vips_embed_paint_edge( embed, + or, i, &todo, p, plsk ); + } + } + + break; + + default: + g_assert( 0 ); + } + + return( 0 ); +} + +static int +vips_embed_build( VipsObject *object ) +{ + VipsConversion *conversion = VIPS_CONVERSION( object ); + VipsEmbed *embed = (VipsEmbed *) object; + + VipsRect want; + + if( VIPS_OBJECT_CLASS( vips_embed_parent_class )->build( object ) ) + return( -1 ); + + if( vips_image_pio_input( embed->input ) || + vips_image_pio_output( conversion->output ) ) + return( -1 ); + if( embed->type < 0 || embed->type > 4 ) { + vips_error( "VipsEmbed", "%s", _( "unknown type" ) ); + return( -1 ); + } + + /* nip can generate this quite often ... just copy. + */ + if( embed->x == 0 && + embed->y == 0 && + embed->width == embed->input->Xsize && + embed->height == embed->input->Ysize ) + return( vips_image_write( embed->input, conversion->output ) ); + + switch( embed->type ) { + case 2: +{ + /* Clock arithmetic: we want negative x/y to wrap around + * nicely. + */ + const int nx = embed->x < 0 ? + -embed->x % embed->input->Xsize : + embed->input->Xsize - embed->x % embed->input->Xsize; + const int ny = embed->y < 0 ? + -embed->y % embed->input->Ysize : + embed->input->Ysize - embed->y % embed->input->Ysize; + + VipsImage *t[1]; + + if( im_open_local_array( conversion->output, + t, 1, "embed-type2", "p" ) || + im_replicate( embed->input, t[0], + embed->width / embed->input->Xsize + 2, + embed->height / embed->input->Ysize + 2 ) || + im_extract_area( t[0], conversion->output, + nx, ny, embed->width, embed->height ) ) + return( -1 ); +} + break; + + case 3: +{ + /* As case 2, but the tiles are twice the size because of + * mirroring. + */ + const int w2 = embed->input->Xsize * 2; + const int h2 = embed->input->Ysize * 2; + + const int nx = embed->x < 0 ? + -embed->x % w2 : w2 - embed->x % w2; + const int ny = embed->y < 0 ? + -embed->y % h2 : h2 - embed->y % h2; + + VipsImage *t[7]; + + if( im_open_local_array( conversion->output, + t, 7, "embed-type3", "p" ) || + /* Cache the edges of in, since we may well be reusing + * them repeatedly. Will only help for tiny borders + * (up to 20 pixels?), but that's our typical case + * with im_conv() etc. + im_cache( in, t[0], IM__TILE_WIDTH, IM__TILE_HEIGHT, + 3 * (in->Xsize / IM__TILE_WIDTH + 1) + + 3 * (in->Ysize / IM__TILE_HEIGHT + 1) ) || + */ + + /* + + FIXME ... alternatively, don't cache, hmm, + need to time this for typical cases + + */ + im_copy( embed->input, t[0] ) || + + /* Make a 2x2 mirror tile. + */ + im_fliphor( t[0], t[1] ) || + im_lrjoin( t[0], t[1], t[2] ) || + im_flipver( t[2], t[3] ) || + im_tbjoin( t[2], t[3], t[4] ) || + + /* Repeat, then cut out the centre. + */ + im_replicate( t[4], t[5], + embed->width / t[4]->Xsize + 2, + embed->height / t[4]->Ysize + 2 ) || + im_extract_area( t[5], t[6], nx, ny, + embed->width, embed->height ) || + + /* Overwrite the centre with the input, much faster + * for centre pixels. + */ + im_insert_noexpand( t[6], embed->input, + conversion->output, embed->x, embed->y ) ) + return( -1 ); +} + break; + + case 0: + case 1: + case 4: + if( vips_image_copy_fields( conversion->output, embed->input ) ) + return( -1 ); + + conversion->output->Xsize = embed->width; + conversion->output->Ysize = embed->height; + + vips_demand_hint( conversion->output, + VIPS_DEMAND_STYLE_SMALLTILE, embed->input, NULL ); + + /* Whole output area. + */ + embed->rout.left = 0; + embed->rout.top = 0; + embed->rout.width = conversion->output->Xsize; + embed->rout.height = conversion->output->Ysize; + + /* Rect occupied by image (can be clipped to nothing). + */ + want.left = embed->x; + want.top = embed->y; + want.width = embed->input->Xsize; + want.height = embed->input->Ysize; + im_rect_intersectrect( &want, &embed->rout, &embed->rsub ); + + /* FIXME ... actually, it can't. embed_find_edge() will fail + * if rsub is empty. Make this more general at some point + * and remove this test. + */ + if( vips_rect_isempty( &embed->rsub ) ) { + vips_error( "VipsEmbed", "%s", _( "bad dimensions" ) ); + return( -1 ); + } + + /* Edge rects of new pixels ... top, right, bottom, left. Order + * important. Can be empty. + */ + embed->border[0].left = embed->rsub.left; + embed->border[0].top = 0; + embed->border[0].width = embed->rsub.width; + embed->border[0].height = embed->rsub.top; + + embed->border[1].left = VIPS_RECT_RIGHT( &embed->rsub ); + embed->border[1].top = embed->rsub.top; + embed->border[1].width = conversion->output->Xsize - + VIPS_RECT_RIGHT( &embed->rsub ); + embed->border[1].height = embed->rsub.height; + + embed->border[2].left = embed->rsub.left; + embed->border[2].top = VIPS_RECT_BOTTOM( &embed->rsub ); + embed->border[2].width = embed->rsub.width; + embed->border[2].height = conversion->output->Ysize - + VIPS_RECT_BOTTOM( &embed->rsub ); + + embed->border[3].left = 0; + embed->border[3].top = embed->rsub.top; + embed->border[3].width = embed->rsub.left; + embed->border[3].height = embed->rsub.height; + + /* Corner rects. Top-left, top-right, bottom-right, + * bottom-left. Order important. + */ + embed->border[4].left = 0; + embed->border[4].top = 0; + embed->border[4].width = embed->rsub.left; + embed->border[4].height = embed->rsub.top; + + embed->border[5].left = VIPS_RECT_RIGHT( &embed->rsub ); + embed->border[5].top = 0; + embed->border[5].width = conversion->output->Xsize - + VIPS_RECT_RIGHT( &embed->rsub ); + embed->border[5].height = embed->rsub.top; + + embed->border[6].left = VIPS_RECT_RIGHT( &embed->rsub ); + embed->border[6].top = VIPS_RECT_BOTTOM( &embed->rsub ); + embed->border[6].width = conversion->output->Xsize - + VIPS_RECT_RIGHT( &embed->rsub ); + embed->border[6].height = conversion->output->Ysize - + VIPS_RECT_BOTTOM( &embed->rsub ); + + embed->border[7].left = 0; + embed->border[7].top = VIPS_RECT_BOTTOM( &embed->rsub ); + embed->border[7].width = embed->rsub.left; + embed->border[7].height = conversion->output->Ysize - + VIPS_RECT_BOTTOM( &embed->rsub ); + + if( vips_image_generate( conversion->output, + vips_start_one, vips_embed_gen, vips_stop_one, + embed->input, embed ) ) + return( -1 ); + + break; + + default: + g_assert( 0 ); + } + + return( 0 ); +} + +static void +vips_embed_class_init( VipsEmbedClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); + + VIPS_DEBUG_MSG( "vips_embed_class_init\n" ); + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + vobject_class->nickname = "embed"; + vobject_class->description = _( "embed an image in a larger image" ); + vobject_class->build = vips_embed_build; + + VIPS_ARG_IMAGE( class, "in", -1, + _( "Input" ), + _( "Input image" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsEmbed, input ) ); + + VIPS_ARG_INT( class, "width", 2, + _( "Width" ), + _( "Image width in pixels" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsEmbed, width ), + 0, 1000000, 0 ); + + VIPS_ARG_INT( class, "height", 3, + _( "Height" ), + _( "Image height in pixels" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsEmbed, height ), + 0, 1000000, 0 ); + + VIPS_ARG_INT( class, "x", 4, + _( "x" ), + _( "Left edge of input in output" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsEmbed, x ), + -1000000, 1000000, 0 ); + + VIPS_ARG_INT( class, "y", 5, + _( "y" ), + _( "Top edge of input in output" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsEmbed, y ), + -1000000, 1000000, 0 ); + + VIPS_ARG_ENUM( class, "type", 6, + _( "type" ), + _( "How to generate the extra pixels" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsEmbed, type ), + VIPS_TYPE_EXTEND, VIPS_EXTEND_BLACK ); +} + +static void +vips_embed_init( VipsEmbed *embed ) +{ + /* Init our instance fields. + */ +} + +int +vips_embed( VipsImage *in, VipsImage **out, + int x, int y, int width, int height, ... ) +{ + va_list ap; + int result; + + va_start( ap, height ); + result = vips_call_split( "embed", ap, + in, out, x, y, width, height ); + va_end( ap ); + + return( result ); +} diff --git a/libvips/deprecated/wrapvips7.c b/libvips/deprecated/wrapvips7.c index be417820..a4964da2 100644 --- a/libvips/deprecated/wrapvips7.c +++ b/libvips/deprecated/wrapvips7.c @@ -775,7 +775,7 @@ vips_wrap7_subclass_class_init( VipsWrap7Class *class ) (type->flags & IM_TYPE_OUTPUT) ? VIPS_ARGUMENT_REQUIRED_OUTPUT : VIPS_ARGUMENT_REQUIRED_INPUT, - i ); + i, i ); break; default: diff --git a/libvips/include/vips/Makefile.am b/libvips/include/vips/Makefile.am index 8226d13e..1f170ac7 100644 --- a/libvips/include/vips/Makefile.am +++ b/libvips/include/vips/Makefile.am @@ -57,6 +57,7 @@ EXTRA_DIST = version.h.in internal.h enumtemplate # well vips_scan_headers = \ ${top_srcdir}/libvips/include/vips/memory.h \ + ${top_srcdir}/libvips/include/vips/conversion.h \ ${top_srcdir}/libvips/include/vips/util.h \ ${top_srcdir}/libvips/include/vips/buf.h \ ${top_srcdir}/libvips/include/vips/image.h \ diff --git a/libvips/include/vips/conversion.h b/libvips/include/vips/conversion.h index 6e9c5e04..81401dc2 100644 --- a/libvips/include/vips/conversion.h +++ b/libvips/include/vips/conversion.h @@ -37,7 +37,49 @@ extern "C" { #endif /*__cplusplus*/ -int vips_copy( VipsImage *in, VipsImage **out, ... ); +/** + * VipsExtend: + * @VIPS_EXTEND_BLACK; extend with black (all 0) pixels + * @VIPS_EXTEND_COPY; copy the image edges + * @VIPS_EXTEND_REPEAT; repeat the whole image + * @VIPS_EXTEND_MIRROR; mirror the whole image + * @VIPS_EXTEND_WHITE; extend with white (all bits set) pixels + * + * See vips_embed(), vips_conv(), vips_affine() and so on. + * + * When the edges of an image are extended, you can specify + * how you want the extension done. + * + * #VIPS_EXTEND_BLACK --- new pixels are black, ie. all bits are zero. + * + * #VIPS_EXTEND_COPY --- each new pixel takes the value of the nearest edge + * pixel + * + * #VIPS_EXTEND_REPEAT --- the image is tiled to fill the new area + * + * #VIPS_EXTEND_MIRROR --- the image is reflected and tiled to reduce hash + * edges + * + * #VIPS_EXTEND_WHITE --- new pixels are white, ie. all bits are set + * + * We have to specify the exact value of each enum member since we have to + * keep these frozen for back compat with vips7. + * + * See also: vips_embed(). + */ +typedef enum { + VIPS_EXTEND_BLACK = 0, + VIPS_EXTEND_COPY = 1, + VIPS_EXTEND_REPEAT = 2, + VIPS_EXTEND_MIRROR = 3, + VIPS_EXTEND_WHITE = 4 +} VipsExtend; + +int vips_copy( VipsImage *in, VipsImage **out, ... ) + __attribute__((sentinel)); +int vips_embed( VipsImage *in, VipsImage **out, + int x, int y, int width, int height, ... ) + __attribute__((sentinel)); diff --git a/libvips/include/vips/enumtypes.h b/libvips/include/vips/enumtypes.h index 95df929c..6d96d032 100644 --- a/libvips/include/vips/enumtypes.h +++ b/libvips/include/vips/enumtypes.h @@ -6,6 +6,9 @@ G_BEGIN_DECLS +/* enumerations from "../../../libvips/include/vips/conversion.h" */ +GType vips_extend_get_type (void) G_GNUC_CONST; +#define VIPS_TYPE_EXTEND (vips_extend_get_type()) /* enumerations from "../../../libvips/include/vips/util.h" */ GType vips_token_get_type (void) G_GNUC_CONST; #define VIPS_TYPE_TOKEN (vips_token_get_type()) diff --git a/libvips/include/vips/image.h b/libvips/include/vips/image.h index fe0b0632..c81f9fa3 100644 --- a/libvips/include/vips/image.h +++ b/libvips/include/vips/image.h @@ -62,23 +62,23 @@ extern "C" { * will use the most restrictive of the styles requested by the operations * in the pipeline. * - * VIPS_DEMAND_STYLE_THINSTRIP --- This operation would like to output strips + * #VIPS_DEMAND_STYLE_THINSTRIP --- This operation would like to output strips * the width of the image and a few pels high. This is option suitable for * point-to-point operations, such as those in the arithmetic package. * * This option is only efficient for cases where each output pel depends * upon the pel in the corresponding position in the input image. * - * VIPS_DEMAND_STYLE_FATSTRIP --- This operation would like to output strips + * #VIPS_DEMAND_STYLE_FATSTRIP --- This operation would like to output strips * the width of the image and as high as possible. This option is suitable * for area operations which do not violently transform coordinates, such * as im_conv(). * - * VIPS_DEMAND_STYLE_SMALLTILE --- This is the most general demand format. + * #VIPS_DEMAND_STYLE_SMALLTILE --- This is the most general demand format. * Output is demanded in small (around 100x100 pel) sections. This style works * reasonably efficiently, even for bizzare operations like 45 degree rotate. * - * VIPS_DEMAND_STYLE_ANY --- This image is not being demand-read from a disc + * #VIPS_DEMAND_STYLE_ANY --- This image is not being demand-read from a disc * file (even indirectly) so any demand style is OK. It's used for things like * im_black() where the pixels are calculated. * diff --git a/libvips/include/vips/object.h b/libvips/include/vips/object.h index 5607a0d2..0ccae099 100644 --- a/libvips/include/vips/object.h +++ b/libvips/include/vips/object.h @@ -52,7 +52,6 @@ typedef struct _VipsObjectClass VipsObjectClass; * @VIPS_ARGUMENT_SET_ONCE: can only be set once * @VIPS_ARGUMENT_INPUT: is an input argument (one we depend on) * @VIPS_ARGUMENT_OUTPUT: is an output argument (depends on us) - * @VIPS_ARGUMENT_APPEND: add to end of arg list (default is prepend) * * Flags we associate with each object argument. * @@ -67,8 +66,7 @@ typedef enum { VIPS_ARGUMENT_CONSTRUCT = 2, VIPS_ARGUMENT_SET_ONCE = 4, VIPS_ARGUMENT_INPUT = 8, - VIPS_ARGUMENT_OUTPUT = 16, - VIPS_ARGUMENT_APPEND = 32 + VIPS_ARGUMENT_OUTPUT = 16 } VipsArgumentFlags; /* Useful flag combinations. User-visible ones are: @@ -108,6 +106,96 @@ VIPS_ARGUMENT_OPTIONAL_OUTPUT Eg. the x pos of the image minimum VIPS_ARGUMENT_CONSTRUCT | \ VIPS_ARGUMENT_SET_ONCE) +extern int _vips__argument_id; + +#define VIPS_ARG_IMAGE( CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET ) { \ + GParamSpec *pspec; \ + \ + pspec = g_param_spec_object( (NAME), (LONG), (DESC), \ + VIPS_TYPE_IMAGE, \ + G_PARAM_READWRITE ); \ + g_object_class_install_property( G_OBJECT_CLASS( CLASS ), \ + _vips__argument_id++, pspec ); \ + vips_object_class_install_argument( VIPS_OBJECT_CLASS( CLASS ), \ + pspec, (FLAGS), (PRIORITY), (OFFSET) ); \ +} + +#define VIPS_ARG_BOOL( CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET, \ + VALUE ) { \ + GParamSpec *pspec; \ + \ + pspec = g_param_spec_boolean( (NAME), (LONG), (DESC), \ + (VALUE), \ + G_PARAM_READWRITE ); \ + g_object_class_install_property( G_OBJECT_CLASS( CLASS ), \ + _vips__argument_id++, pspec ); \ + vips_object_class_install_argument( VIPS_OBJECT_CLASS( CLASS ), \ + pspec, (FLAGS), (PRIORITY), (OFFSET) ); \ +} + +#define VIPS_ARG_DOUBLE( CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET, \ + MIN, MAX, VALUE ) { \ + GParamSpec *pspec; \ + \ + pspec = g_param_spec_double( (NAME), (LONG), (DESC), \ + (MIN), (MAX), (VALUE), \ + G_PARAM_READWRITE );\ + g_object_class_install_property( G_OBJECT_CLASS( CLASS ), \ + _vips__argument_id++, pspec ); \ + vips_object_class_install_argument( VIPS_OBJECT_CLASS( CLASS ), \ + pspec, (FLAGS), (PRIORITY), (OFFSET) ); \ +} + +#define VIPS_ARG_INT( CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET, \ + MIN, MAX, VALUE ) { \ + GParamSpec *pspec; \ + \ + pspec = g_param_spec_int( (NAME), (LONG), (DESC), \ + (MIN), (MAX), (VALUE), \ + G_PARAM_READWRITE );\ + g_object_class_install_property( G_OBJECT_CLASS( CLASS ), \ + _vips__argument_id++, pspec ); \ + vips_object_class_install_argument( VIPS_OBJECT_CLASS( CLASS ), \ + pspec, (FLAGS), (PRIORITY), (OFFSET) ); \ +} + +#define VIPS_ARG_ENUM( CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET, \ + TYPE, VALUE ) { \ + GParamSpec *pspec; \ + \ + pspec = g_param_spec_enum( (NAME), (LONG), (DESC), \ + (TYPE), (VALUE), \ + G_PARAM_READWRITE );\ + g_object_class_install_property( G_OBJECT_CLASS( CLASS ), \ + _vips__argument_id++, pspec ); \ + vips_object_class_install_argument( VIPS_OBJECT_CLASS( CLASS ), \ + pspec, (FLAGS), (PRIORITY), (OFFSET) ); \ +} + +#define VIPS_ARG_STRING( CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET, \ + VALUE ) { \ + GParamSpec *pspec; \ + \ + pspec = g_param_spec_string( (NAME), (LONG), (DESC), \ + (VALUE), \ + G_PARAM_READWRITE ); \ + g_object_class_install_property( G_OBJECT_CLASS( CLASS ), \ + _vips__argument_id++, pspec ); \ + vips_object_class_install_argument( VIPS_OBJECT_CLASS( CLASS ), \ + pspec, (FLAGS), (PRIORITY), (OFFSET) ); \ +} + +#define VIPS_ARG_POINTER( CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET ) { \ + GParamSpec *pspec; \ + \ + pspec = g_param_spec_pointer( (NAME), (LONG), (DESC), \ + G_PARAM_READWRITE ); \ + g_object_class_install_property( gobject_class, \ + _vips__argument_id++, pspec ); \ + vips_object_class_install_argument( VIPS_OBJECT_CLASS( CLASS ), \ + pspec, (FLAGS), (PRIORITY), (OFFSET) ); \ +} + /* Keep one of these for every argument. */ typedef struct _VipsArgument { @@ -126,6 +214,7 @@ typedef struct _VipsArgumentClass { VipsObjectClass *object_class; VipsArgumentFlags flags; + int priority; /* Order args by this */ guint offset; /* G_STRUCT_OFFSET of member in object */ } VipsArgumentClass; @@ -332,8 +421,8 @@ gboolean vips_object_sanity( VipsObject *object ); GType vips_object_get_type( void ); -void vips_object_class_install_argument( VipsObjectClass *, - GParamSpec *pspec, VipsArgumentFlags flags, guint offset ); +void vips_object_class_install_argument( VipsObjectClass *, GParamSpec *pspec, + VipsArgumentFlags flags, int priority, guint offset ); int vips_object_set_argument_from_string( VipsObject *object, const char *name, const char *value ); gboolean vips_object_get_argument_needs_string( VipsObject *object, diff --git a/libvips/iofuncs/Makefile.am b/libvips/iofuncs/Makefile.am index 4f124be1..bb4ce137 100644 --- a/libvips/iofuncs/Makefile.am +++ b/libvips/iofuncs/Makefile.am @@ -41,6 +41,7 @@ INCLUDES = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@ # well vips_scan_headers = \ ${top_srcdir}/libvips/include/vips/memory.h \ + ${top_srcdir}/libvips/include/vips/conversion.h \ ${top_srcdir}/libvips/include/vips/util.h \ ${top_srcdir}/libvips/include/vips/buf.h \ ${top_srcdir}/libvips/include/vips/image.h \ diff --git a/libvips/iofuncs/enumtypes.c b/libvips/iofuncs/enumtypes.c index c87c2e9f..6f158c5b 100644 --- a/libvips/iofuncs/enumtypes.c +++ b/libvips/iofuncs/enumtypes.c @@ -4,6 +4,27 @@ /* auto-generated enums for vips introspection */ #include +/* enumerations from "../../libvips/include/vips/conversion.h" */ +GType +vips_extend_get_type( void ) +{ + static GType etype = 0; + + if( etype == 0 ) { + static const GEnumValue values[] = { + {VIPS_EXTEND_BLACK, "VIPS_EXTEND_BLACK", "black"}, + {VIPS_EXTEND_COPY, "VIPS_EXTEND_COPY", "copy"}, + {VIPS_EXTEND_REPEAT, "VIPS_EXTEND_REPEAT", "repeat"}, + {VIPS_EXTEND_MIRROR, "VIPS_EXTEND_MIRROR", "mirror"}, + {VIPS_EXTEND_WHITE, "VIPS_EXTEND_WHITE", "white"}, + {0, NULL, NULL} + }; + + etype = g_enum_register_static( "VipsExtend", values ); + } + + return( etype ); +} /* enumerations from "../../libvips/include/vips/util.h" */ GType vips_token_get_type( void ) @@ -158,7 +179,6 @@ vips_argument_flags_get_type( void ) {VIPS_ARGUMENT_SET_ONCE, "VIPS_ARGUMENT_SET_ONCE", "set-once"}, {VIPS_ARGUMENT_INPUT, "VIPS_ARGUMENT_INPUT", "input"}, {VIPS_ARGUMENT_OUTPUT, "VIPS_ARGUMENT_OUTPUT", "output"}, - {VIPS_ARGUMENT_APPEND, "VIPS_ARGUMENT_APPEND", "append"}, {0, NULL, NULL} }; diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c index bd6e06a0..ceade629 100644 --- a/libvips/iofuncs/image.c +++ b/libvips/iofuncs/image.c @@ -143,28 +143,6 @@ * Returns: The address of pixel (x,y) in the image. */ -/* Properties. - */ -enum { - PROP_WIDTH = 1, - PROP_HEIGHT, - PROP_BANDS, - PROP_FORMAT, - PROP_CODING, - PROP_INTERPRETATION, - PROP_XRES, - PROP_YRES, - PROP_XOFFSET, - PROP_YOFFSET, - PROP_FILENAME, - PROP_KILL, - PROP_MODE, - PROP_DEMAND, - PROP_SIZEOF_HEADER, - PROP_FOREIGN_BUFFER, - PROP_LAST -}; - /* Our signals. */ enum { @@ -938,12 +916,11 @@ vips_image_class_init( VipsImageClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); - GParamSpec *pspec; VIPS_DEBUG_MSG( "vips_image_class_init:\n" ); /* Pass in a nonsense name for argv0 ... this init world is only here - * for old programs which are missing an vips_init() call. We must + * for old programs which are missing a vips_init() call. We must * have threads set up before we can process. */ if( vips_init( "vips" ) ) @@ -972,149 +949,114 @@ vips_image_class_init( VipsImageClass *class ) /* Create properties. */ - /* Width / height / bands can be zero for unintialised. - */ - pspec = g_param_spec_int( "width", "Width", + VIPS_ARG_INT( class, "width", 2, + _( "Width" ), _( "Image width in pixels" ), - 0, 1000000, 0, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_WIDTH, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_SET_ONCE, - G_STRUCT_OFFSET( VipsImage, Xsize ) ); - pspec = g_param_spec_int( "height", "Height", + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsImage, Xsize ), + 0, 1000000, 0 ); + + VIPS_ARG_INT( class, "height", 3, + _( "Height" ), _( "Image height in pixels" ), - 0, 1000000, 0, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_HEIGHT, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_SET_ONCE, - G_STRUCT_OFFSET( VipsImage, Ysize ) ); - pspec = g_param_spec_int( "bands", "Bands", + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsImage, Ysize ), + 0, 1000000, 0 ); + + VIPS_ARG_INT( class, "bands", 4, + _( "Bands" ), _( "Number of bands in image" ), - 0, 1000000, 0, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_BANDS, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_SET_ONCE, - G_STRUCT_OFFSET( VipsImage, Bands ) ); + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsImage, Bands ), + 0, 1000000, 0 ); - pspec = g_param_spec_enum( "format", "Format", + VIPS_ARG_ENUM( class, "format", 5, + _( "Format" ), _( "Pixel format in image" ), - VIPS_TYPE_BAND_FORMAT, VIPS_FORMAT_UCHAR, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_FORMAT, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_SET_ONCE, - G_STRUCT_OFFSET( VipsImage, BandFmt ) ); + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsImage, BandFmt ), + VIPS_TYPE_BAND_FORMAT, VIPS_FORMAT_UCHAR ); - pspec = g_param_spec_enum( "coding", "Coding", + VIPS_ARG_ENUM( class, "coding", 6, + _( "Coding" ), _( "Pixel coding" ), - VIPS_TYPE_CODING, VIPS_CODING_NONE, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_CODING, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_SET_ONCE, - G_STRUCT_OFFSET( VipsImage, Coding ) ); + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsImage, Coding ), + VIPS_TYPE_CODING, VIPS_CODING_NONE ); - pspec = g_param_spec_enum( "interpretation", "Interpretation", + VIPS_ARG_ENUM( class, "interpretation", 7, + _( "Interpretation" ), _( "Pixel interpretation" ), - VIPS_TYPE_INTERPRETATION, VIPS_INTERPRETATION_MULTIBAND, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, - PROP_INTERPRETATION, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_SET_ONCE, - G_STRUCT_OFFSET( VipsImage, Type ) ); + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsImage, Type ), + VIPS_TYPE_INTERPRETATION, VIPS_INTERPRETATION_MULTIBAND ); - pspec = g_param_spec_double( "xres", "XRes", + VIPS_ARG_DOUBLE( class, "xres", 8, + _( "Xres" ), _( "Horizontal resolution in pixels/mm" ), - 0, 1000000, 0, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_XRES, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_SET_ONCE, - G_STRUCT_OFFSET( VipsImage, Xres ) ); + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsImage, Xres ), + 0, 1000000, 0 ); - pspec = g_param_spec_double( "yres", "YRes", + VIPS_ARG_DOUBLE( class, "yres", 9, + _( "Yres" ), _( "Vertical resolution in pixels/mm" ), - 0, 1000000, 0, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_YRES, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_SET_ONCE, - G_STRUCT_OFFSET( VipsImage, Yres ) ); + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsImage, Yres ), + 0, 1000000, 0 ); - pspec = g_param_spec_int( "xoffset", "XOffset", + VIPS_ARG_INT( class, "xoffset", 10, + _( "Xoffset" ), _( "Horizontal offset of origin" ), - -10000000, 1000000, 0, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_XOFFSET, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_SET_ONCE, - G_STRUCT_OFFSET( VipsImage, Xoffset ) ); + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsImage, Xoffset ), + -1000000, 1000000, 0 ); - pspec = g_param_spec_int( "yoffset", "YOffset", + VIPS_ARG_INT( class, "yoffset", 11, + _( "Yoffset" ), _( "Vertical offset of origin" ), - -10000000, 1000000, 0, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_YOFFSET, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_SET_ONCE, - G_STRUCT_OFFSET( VipsImage, Yoffset ) ); + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsImage, Yoffset ), + -1000000, 1000000, 0 ); - pspec = g_param_spec_string( "filename", "Filename", + VIPS_ARG_STRING( class, "filename", 12, + _( "Filename" ), _( "Image filename" ), - NULL, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_FILENAME, pspec ); - vips_object_class_install_argument( vobject_class, pspec, VIPS_ARGUMENT_CONSTRUCT, - G_STRUCT_OFFSET( VipsImage, filename ) ); + G_STRUCT_OFFSET( VipsImage, filename ), + NULL ); - pspec = g_param_spec_string( "mode", "Mode", + VIPS_ARG_STRING( class, "mode", 13, + _( "Mode" ), _( "Open mode" ), - "p", /* Default to partial */ - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_MODE, pspec ); - vips_object_class_install_argument( vobject_class, pspec, VIPS_ARGUMENT_CONSTRUCT, - G_STRUCT_OFFSET( VipsImage, mode ) ); + G_STRUCT_OFFSET( VipsImage, filename ), + "p" ); - pspec = g_param_spec_boolean( "kill", "Kill", + VIPS_ARG_BOOL( class, "kill", 14, + _( "Kill" ), _( "Block evaluation on this image" ), - FALSE, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_KILL, pspec ); - vips_object_class_install_argument( vobject_class, pspec, VIPS_ARGUMENT_NONE, - G_STRUCT_OFFSET( VipsImage, kill ) ); + G_STRUCT_OFFSET( VipsImage, kill ), + FALSE ); - pspec = g_param_spec_enum( "demand", "Demand", + VIPS_ARG_ENUM( class, "demand", 15, + _( "Demand style" ), _( "Preferred demand style for this image" ), - VIPS_TYPE_DEMAND_STYLE, VIPS_DEMAND_STYLE_SMALLTILE, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, PROP_DEMAND, pspec ); - vips_object_class_install_argument( vobject_class, pspec, - VIPS_ARGUMENT_NONE, - G_STRUCT_OFFSET( VipsImage, dhint ) ); + VIPS_ARGUMENT_NONE, + G_STRUCT_OFFSET( VipsImage, dhint ), + VIPS_TYPE_DEMAND_STYLE, VIPS_DEMAND_STYLE_SMALLTILE ); - pspec = g_param_spec_int( "sizeof_header", "Size of header", + VIPS_ARG_INT( class, "sizeof_header", 16, + _( "Size of header" ), _( "Offset in bytes from start of file" ), - 0, 1000000, VIPS_SIZEOF_HEADER, - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, - PROP_SIZEOF_HEADER, pspec ); - vips_object_class_install_argument( vobject_class, pspec, VIPS_ARGUMENT_SET_ONCE | VIPS_ARGUMENT_CONSTRUCT, - G_STRUCT_OFFSET( VipsImage, sizeof_header ) ); + G_STRUCT_OFFSET( VipsImage, sizeof_header ), + 0, 1000000, VIPS_SIZEOF_HEADER ); - pspec = g_param_spec_pointer( "foreign_buffer", "Foreign buffer", - "Pointer to foreign pixels", - G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, - PROP_FOREIGN_BUFFER, pspec ); - vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARG_POINTER( class, "foreign_buffer", 17, + _( "Foreign buffer" ), + _( "Pointer to foreign pixels" ), VIPS_ARGUMENT_SET_ONCE | VIPS_ARGUMENT_CONSTRUCT, G_STRUCT_OFFSET( VipsImage, data ) ); diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index 96b468a2..2151cd74 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -48,14 +48,6 @@ #include #include -/* Properties. - */ -enum { - PROP_NICKNAME = 1,/* Class properties as object props */ - PROP_DESCRIPTION, - PROP_LAST -}; - /* Our signals. */ enum { @@ -72,6 +64,8 @@ static GMutex *vips__object_all_lock = NULL; static guint vips_object_signals[SIG_LAST] = { 0 }; +int _vips__argument_id = 0; + G_DEFINE_ABSTRACT_TYPE( VipsObject, vips_object, G_TYPE_OBJECT ); void @@ -1058,8 +1052,6 @@ vips_object_class_init( VipsObjectClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); - GParamSpec *pspec; - if( !vips__object_all ) { vips__object_all = g_hash_table_new( g_direct_hash, g_direct_equal ); @@ -1092,29 +1084,19 @@ vips_object_class_init( VipsObjectClass *class ) g_value_register_transform_func( G_TYPE_STRING, G_TYPE_DOUBLE, transform_string_double ); - /* Create properties. - */ - pspec = g_param_spec_string( "nickname", + VIPS_ARG_STRING( class, "nickname", 1, _( "Nickname" ), _( "Class nickname" ), - "", - (GParamFlags) G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, - PROP_NICKNAME, pspec ); - vips_object_class_install_argument( class, pspec, VIPS_ARGUMENT_SET_ONCE, - G_STRUCT_OFFSET( VipsObject, nickname ) ); + G_STRUCT_OFFSET( VipsObject, nickname ), + "" ); - pspec = g_param_spec_string( "description", + VIPS_ARG_STRING( class, "description", 2, _( "Description" ), _( "Class description" ), - "", - (GParamFlags) G_PARAM_READWRITE ); - g_object_class_install_property( gobject_class, - PROP_DESCRIPTION, pspec ); - vips_object_class_install_argument( class, pspec, VIPS_ARGUMENT_SET_ONCE, - G_STRUCT_OFFSET( VipsObject, description ) ); + G_STRUCT_OFFSET( VipsObject, description ), + "" ); vips_object_signals[SIG_PRECLOSE] = g_signal_new( "preclose", G_TYPE_FROM_CLASS( class ), @@ -1154,11 +1136,20 @@ vips_object_init( VipsObject *object ) g_mutex_unlock( vips__object_all_lock ); } +static gint +traverse_sort( gconstpointer a, gconstpointer b ) +{ + VipsArgumentClass *class1 = (VipsArgumentClass *) a; + VipsArgumentClass *class2 = (VipsArgumentClass *) b; + + return( class1->priority - class2->priority ); +} + /* Add a vipsargument ... automate some stuff with this. */ void vips_object_class_install_argument( VipsObjectClass *object_class, - GParamSpec *pspec, VipsArgumentFlags flags, guint offset ) + GParamSpec *pspec, VipsArgumentFlags flags, int priority, guint offset ) { VipsArgumentClass *argument_class = g_new( VipsArgumentClass, 1 ); @@ -1181,16 +1172,15 @@ vips_object_class_install_argument( VipsObjectClass *object_class, ((VipsArgument *) argument_class)->pspec = pspec; argument_class->object_class = object_class; argument_class->flags = flags; + argument_class->priority = priority; argument_class->offset = offset; vips_argument_table_replace( object_class->argument_table, (VipsArgument *) argument_class ); - if( flags & VIPS_ARGUMENT_APPEND ) - object_class->argument_table_traverse = g_slist_append( - object_class->argument_table_traverse, argument_class ); - else - object_class->argument_table_traverse = g_slist_prepend( - object_class->argument_table_traverse, argument_class ); + object_class->argument_table_traverse = g_slist_prepend( + object_class->argument_table_traverse, argument_class ); + object_class->argument_table_traverse = g_slist_sort( + object_class->argument_table_traverse, traverse_sort ); } /* Set a named arg from a string.