diff --git a/ChangeLog b/ChangeLog index 4d16c99d..9ba2efa2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,7 @@ - hough_line scales width to 0 - 180, not 0 - 360 - hough_line is 4x faster - hough_circle is 2x faster +- add vips_rotate() ... a convenience method for vips_similarity() 12/2/18 started 8.6.3 - use pkg-config to find libjpeg, if we can diff --git a/libvips/include/vips/resample.h b/libvips/include/vips/resample.h index d01d118c..eafe658c 100644 --- a/libvips/include/vips/resample.h +++ b/libvips/include/vips/resample.h @@ -81,6 +81,8 @@ int vips_thumbnail_image( VipsImage *in, VipsImage **out, int width, ... ) int vips_similarity( VipsImage *in, VipsImage **out, ... ) __attribute__((sentinel)); +int vips_rotate( VipsImage *in, VipsImage **out, double angle, ... ) + __attribute__((sentinel)); int vips_affine( VipsImage *in, VipsImage **out, double a, double b, double c, double d, ... ) __attribute__((sentinel)); diff --git a/libvips/resample/resample.c b/libvips/resample/resample.c index 36980d43..1a48c9c8 100644 --- a/libvips/resample/resample.c +++ b/libvips/resample/resample.c @@ -167,6 +167,7 @@ vips_resample_operation_init( void ) extern GType vips_quadratic_get_type( void ); extern GType vips_affine_get_type( void ); extern GType vips_similarity_get_type( void ); + extern GType vips_rotate_get_type( void ); extern GType vips_resize_get_type( void ); vips_thumbnail_file_get_type(); @@ -182,6 +183,7 @@ vips_resample_operation_init( void ) vips_quadratic_get_type(); vips_affine_get_type(); vips_similarity_get_type(); + vips_rotate_get_type(); vips_resize_get_type(); } diff --git a/libvips/resample/similarity.c b/libvips/resample/similarity.c index 106dfaa5..e639a3d2 100644 --- a/libvips/resample/similarity.c +++ b/libvips/resample/similarity.c @@ -13,6 +13,8 @@ * 17/11/17 * ` - add optional "background" param * ` - don't use vips_reduce() since it has no "background" param + * 10/3/18 + * - add vips_rotate() class for convenience */ /* @@ -58,46 +60,48 @@ #include "presample.h" -typedef struct _VipsSimilarity { +typedef struct _VipsSimilarityBase { VipsResample parent_instance; double scale; double angle; VipsInterpolate *interpolate; + VipsArrayDouble *background; double odx; double ody; double idx; double idy; - VipsArrayDouble *background; -} VipsSimilarity; +} VipsSimilarityBase; -typedef VipsResampleClass VipsSimilarityClass; +typedef VipsResampleClass VipsSimilarityBaseClass; -G_DEFINE_TYPE( VipsSimilarity, vips_similarity, VIPS_TYPE_RESAMPLE ); +G_DEFINE_ABSTRACT_TYPE( VipsSimilarityBase, vips_similarity_base, + VIPS_TYPE_RESAMPLE ); static int -vips_similarity_build( VipsObject *object ) +vips_similarity_base_build( VipsObject *object ) { VipsResample *resample = VIPS_RESAMPLE( object ); - VipsSimilarity *similarity = (VipsSimilarity *) object; + VipsSimilarityBase *base = (VipsSimilarityBase *) object; VipsImage **t = (VipsImage **) vips_object_local_array( object, 4 ); - double a = similarity->scale * cos( VIPS_RAD( similarity->angle ) ); - double b = similarity->scale * -sin( VIPS_RAD( similarity->angle ) ); + double a = base->scale * cos( VIPS_RAD( base->angle ) ); + double b = base->scale * -sin( VIPS_RAD( base->angle ) ); double c = -b; double d = a; - if( VIPS_OBJECT_CLASS( vips_similarity_parent_class )->build( object ) ) + if( VIPS_OBJECT_CLASS( vips_similarity_base_parent_class )-> + build( object ) ) return( -1 ); if( vips_affine( resample->in, &t[0], a, b, c, d, - "interpolate", similarity->interpolate, - "odx", similarity->odx, - "ody", similarity->ody, - "idx", similarity->idx, - "idy", similarity->idy, - "background", similarity->background, + "interpolate", base->interpolate, + "odx", base->odx, + "ody", base->ody, + "idx", base->idx, + "idy", base->idy, + "background", base->background, NULL ) ) return( -1 ); @@ -107,6 +111,81 @@ vips_similarity_build( VipsObject *object ) return( 0 ); } +static void +vips_similarity_base_class_init( VipsSimilarityBaseClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + vobject_class->nickname = "similarity_base"; + vobject_class->description = _( "base similarity transform" ); + vobject_class->build = vips_similarity_base_build; + + VIPS_ARG_INTERPOLATE( class, "interpolate", 5, + _( "Interpolate" ), + _( "Interpolate pixels with this" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsSimilarityBase, interpolate ) ); + + VIPS_ARG_BOXED( class, "background", 6, + _( "Background" ), + _( "Background value" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsSimilarityBase, background ), + VIPS_TYPE_ARRAY_DOUBLE ); + + VIPS_ARG_DOUBLE( class, "odx", 112, + _( "Output offset" ), + _( "Horizontal output displacement" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsSimilarityBase, odx ), + -10000000, 10000000, 0 ); + + VIPS_ARG_DOUBLE( class, "ody", 113, + _( "Output offset" ), + _( "Vertical output displacement" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsSimilarityBase, ody ), + -10000000, 10000000, 0 ); + + VIPS_ARG_DOUBLE( class, "idx", 114, + _( "Input offset" ), + _( "Horizontal input displacement" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsSimilarityBase, idx ), + -10000000, 10000000, 0 ); + + VIPS_ARG_DOUBLE( class, "idy", 115, + _( "Input offset" ), + _( "Vertical input displacement" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsSimilarityBase, idy ), + -10000000, 10000000, 0 ); + +} + +static void +vips_similarity_base_init( VipsSimilarityBase *base ) +{ + base->scale = 1; + base->angle = 0; + base->interpolate = NULL; + base->odx = 0; + base->ody = 0; + base->idx = 0; + base->idy = 0; + base->background = vips_array_double_newv( 1, 0.0 ); +} + +typedef VipsSimilarityBase VipsSimilarity; +typedef VipsSimilarityBaseClass VipsSimilarityClass; + +G_DEFINE_TYPE( VipsSimilarity, vips_similarity, + vips_similarity_base_get_type() ); + static void vips_similarity_class_init( VipsSimilarityClass *class ) { @@ -118,7 +197,6 @@ vips_similarity_class_init( VipsSimilarityClass *class ) vobject_class->nickname = "similarity"; vobject_class->description = _( "similarity transform of an image" ); - vobject_class->build = vips_similarity_build; VIPS_ARG_DOUBLE( class, "scale", 3, _( "Scale" ), @@ -134,59 +212,11 @@ vips_similarity_class_init( VipsSimilarityClass *class ) G_STRUCT_OFFSET( VipsSimilarity, angle ), -10000000, 10000000, 0 ); - VIPS_ARG_INTERPOLATE( class, "interpolate", 2, - _( "Interpolate" ), - _( "Interpolate pixels with this" ), - VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsSimilarity, interpolate ) ); - - VIPS_ARG_DOUBLE( class, "odx", 112, - _( "Output offset" ), - _( "Horizontal output displacement" ), - VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsSimilarity, odx ), - -10000000, 10000000, 0 ); - - VIPS_ARG_DOUBLE( class, "ody", 113, - _( "Output offset" ), - _( "Vertical output displacement" ), - VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsSimilarity, ody ), - -10000000, 10000000, 0 ); - - VIPS_ARG_DOUBLE( class, "idx", 114, - _( "Input offset" ), - _( "Horizontal input displacement" ), - VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsSimilarity, idx ), - -10000000, 10000000, 0 ); - - VIPS_ARG_DOUBLE( class, "idy", 115, - _( "Input offset" ), - _( "Vertical input displacement" ), - VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsSimilarity, idy ), - -10000000, 10000000, 0 ); - - VIPS_ARG_BOXED( class, "background", 2, - _( "Background" ), - _( "Background value" ), - VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsSimilarity, background ), - VIPS_TYPE_ARRAY_DOUBLE ); } static void vips_similarity_init( VipsSimilarity *similarity ) { - similarity->scale = 1; - similarity->angle = 0; - similarity->interpolate = NULL; - similarity->odx = 0; - similarity->ody = 0; - similarity->idx = 0; - similarity->idy = 0; - similarity->background = vips_array_double_newv( 1, 0.0 ); } /** @@ -200,12 +230,12 @@ vips_similarity_init( VipsSimilarity *similarity ) * * @scale: %gdouble, scale by this factor * * @angle: %gdouble, rotate by this many degrees clockwise * * @interpolate: #VipsInterpolate, interpolate pixels with this + * * @background: #VipsArrayDouble colour for new pixels * * @idx: %gdouble, input horizontal offset * * @idy: %gdouble, input vertical offset * * @odx: %gdouble, output horizontal offset * * @ody: %gdouble, output vertical offset * * @ody: %gdouble, output vertical offset - * * @background: #VipsArrayDouble colour for new pixels * * This operator calls vips_affine() for you, calculating the matrix for the * affine transform from @scale and @angle. Other parameters are passed on to @@ -227,3 +257,73 @@ vips_similarity( VipsImage *in, VipsImage **out, ... ) return( result ); } + +typedef VipsSimilarityBase VipsRotate; +typedef VipsSimilarityBaseClass VipsRotateClass; + +G_DEFINE_TYPE( VipsRotate, vips_rotate, vips_similarity_base_get_type() ); + +static void +vips_rotate_class_init( VipsRotateClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + vobject_class->nickname = "rotate"; + vobject_class->description = + _( "rotate an image by a number of degrees" ); + + VIPS_ARG_DOUBLE( class, "angle", 4, + _( "Angle" ), + _( "Rotate anticlockwise by this many degrees" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsSimilarity, angle ), + -10000000, 10000000, 0 ); + +} + +static void +vips_rotate_init( VipsRotate *rotate ) +{ +} + +/** + * vips_rotate: (method) + * @in: input image + * @out: (out): output image + * @angle: %gdouble, rotate by this many degrees clockwise + * @...: %NULL-terminated list of optional named arguments + * + * Optional arguments: + * + * * @interpolate: #VipsInterpolate, interpolate pixels with this + * * @background: #VipsArrayDouble colour for new pixels + * * @idx: %gdouble, input horizontal offset + * * @idy: %gdouble, input vertical offset + * * @odx: %gdouble, output horizontal offset + * * @ody: %gdouble, output vertical offset + * * @ody: %gdouble, output vertical offset + * + * This operator calls vips_affine() for you, calculating the matrix for the + * affine transform from @scale and @angle. Other parameters are passed on to + * vips_affine() unaltered. + * + * See also: vips_affine(), #VipsInterpolate. + * + * Returns: 0 on success, -1 on error + */ +int +vips_rotate( VipsImage *in, VipsImage **out, double angle, ... ) +{ + va_list ap; + int result; + + va_start( ap, angle ); + result = vips_call_split( "rotate", ap, in, out, angle ); + va_end( ap ); + + return( result ); +}