1 /* simple wrapper over vips_affine() to make scale / rotate easy from the
2  * command-line
3  *
4  * 3/10/13
5  * 	- from affine.c
6  * 25/10/13
7  * 	- oops, reverse rotation direction to match the convention used in the
8  * 	  rest of vips
9  * 13/8/14
10  * 	- oops, missing scale from b, thanks Topochicho
11  * 7/2/16
12  * 	- use vips_reduce(), if we can
13  * 17/11/17
14  * `	- add optional "background" param
15  * `	- don't use vips_reduce() since it has no "background" param
16  * 10/3/18
17  * 	- add vips_rotate() class for convenience
18  */
19 
20 /*
21 
22     This file is part of VIPS.
23 
24     VIPS is free software; you can redistribute it and/or modify
25     it under the terms of the GNU Lesser General Public License as published by
26     the Free Software Foundation; either version 2 of the License, or
27     (at your option) any later version.
28 
29     This program is distributed in the hope that it will be useful,
30     but WITHOUT ANY WARRANTY; without even the implied warranty of
31     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32     GNU Lesser General Public License for more details.
33 
34     You should have received a copy of the GNU Lesser General Public License
35     along with this program; if not, write to the Free Software
36     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
37     02110-1301  USA
38 
39  */
40 
41 /*
42 
43     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
44 
45  */
46 
47 /*
48 #define DEBUG
49  */
50 
51 #ifdef HAVE_CONFIG_H
52 #include <config.h>
53 #endif /*HAVE_CONFIG_H*/
54 #include <vips/intl.h>
55 
56 #include <math.h>
57 #include <string.h>
58 
59 #include <vips/vips.h>
60 
61 #include "presample.h"
62 
63 typedef struct _VipsSimilarityBase {
64 	VipsResample parent_instance;
65 
66 	double scale;
67 	double angle;
68 	VipsInterpolate *interpolate;
69 	VipsArrayDouble *background;
70 	double odx;
71 	double ody;
72 	double idx;
73 	double idy;
74 
75 } VipsSimilarityBase;
76 
77 typedef VipsResampleClass VipsSimilarityBaseClass;
78 
79 G_DEFINE_ABSTRACT_TYPE( VipsSimilarityBase, vips_similarity_base,
80 	VIPS_TYPE_RESAMPLE );
81 
82 static int
vips_similarity_base_build(VipsObject * object)83 vips_similarity_base_build( VipsObject *object )
84 {
85 	VipsResample *resample = VIPS_RESAMPLE( object );
86 	VipsSimilarityBase *base = (VipsSimilarityBase *) object;
87 	VipsImage **t = (VipsImage **)
88 		vips_object_local_array( object, 4 );
89 	double a = base->scale * cos( VIPS_RAD( base->angle ) );
90 	double b = base->scale * -sin( VIPS_RAD( base->angle ) );
91 	double c = -b;
92 	double d = a;
93 
94 	if( VIPS_OBJECT_CLASS( vips_similarity_base_parent_class )->
95 		build( object ) )
96 		return( -1 );
97 
98 	if( vips_affine( resample->in, &t[0], a, b, c, d,
99 		"interpolate", base->interpolate,
100 		"odx", base->odx,
101 		"ody", base->ody,
102 		"idx", base->idx,
103 		"idy", base->idy,
104 		"background", base->background,
105 		NULL ) )
106 		return( -1 );
107 
108 	if( vips_image_write( t[0], resample->out ) )
109 		return( -1 );
110 
111 	return( 0 );
112 }
113 
114 static void
vips_similarity_base_class_init(VipsSimilarityBaseClass * class)115 vips_similarity_base_class_init( VipsSimilarityBaseClass *class )
116 {
117 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
118 	VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
119 
120 	gobject_class->set_property = vips_object_set_property;
121 	gobject_class->get_property = vips_object_get_property;
122 
123 	vobject_class->nickname = "similarity_base";
124 	vobject_class->description = _( "base similarity transform" );
125 	vobject_class->build = vips_similarity_base_build;
126 
127 	VIPS_ARG_INTERPOLATE( class, "interpolate", 5,
128 		_( "Interpolate" ),
129 		_( "Interpolate pixels with this" ),
130 		VIPS_ARGUMENT_OPTIONAL_INPUT,
131 		G_STRUCT_OFFSET( VipsSimilarityBase, interpolate ) );
132 
133 	VIPS_ARG_BOXED( class, "background", 6,
134 		_( "Background" ),
135 		_( "Background value" ),
136 		VIPS_ARGUMENT_OPTIONAL_INPUT,
137 		G_STRUCT_OFFSET( VipsSimilarityBase, background ),
138 		VIPS_TYPE_ARRAY_DOUBLE );
139 
140 	VIPS_ARG_DOUBLE( class, "odx", 112,
141 		_( "Output offset" ),
142 		_( "Horizontal output displacement" ),
143 		VIPS_ARGUMENT_OPTIONAL_INPUT,
144 		G_STRUCT_OFFSET( VipsSimilarityBase, odx ),
145 		-10000000, 10000000, 0 );
146 
147 	VIPS_ARG_DOUBLE( class, "ody", 113,
148 		_( "Output offset" ),
149 		_( "Vertical output displacement" ),
150 		VIPS_ARGUMENT_OPTIONAL_INPUT,
151 		G_STRUCT_OFFSET( VipsSimilarityBase, ody ),
152 		-10000000, 10000000, 0 );
153 
154 	VIPS_ARG_DOUBLE( class, "idx", 114,
155 		_( "Input offset" ),
156 		_( "Horizontal input displacement" ),
157 		VIPS_ARGUMENT_OPTIONAL_INPUT,
158 		G_STRUCT_OFFSET( VipsSimilarityBase, idx ),
159 		-10000000, 10000000, 0 );
160 
161 	VIPS_ARG_DOUBLE( class, "idy", 115,
162 		_( "Input offset" ),
163 		_( "Vertical input displacement" ),
164 		VIPS_ARGUMENT_OPTIONAL_INPUT,
165 		G_STRUCT_OFFSET( VipsSimilarityBase, idy ),
166 		-10000000, 10000000, 0 );
167 
168 }
169 
170 static void
vips_similarity_base_init(VipsSimilarityBase * base)171 vips_similarity_base_init( VipsSimilarityBase *base )
172 {
173 	base->scale = 1;
174 	base->angle = 0;
175 	base->interpolate = NULL;
176 	base->odx = 0;
177 	base->ody = 0;
178 	base->idx = 0;
179 	base->idy = 0;
180 	base->background = vips_array_double_newv( 1, 0.0 );
181 }
182 
183 typedef VipsSimilarityBase VipsSimilarity;
184 typedef VipsSimilarityBaseClass VipsSimilarityClass;
185 
186 G_DEFINE_TYPE( VipsSimilarity, vips_similarity,
187 	vips_similarity_base_get_type() );
188 
189 static void
vips_similarity_class_init(VipsSimilarityClass * class)190 vips_similarity_class_init( VipsSimilarityClass *class )
191 {
192 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
193 	VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
194 
195 	gobject_class->set_property = vips_object_set_property;
196 	gobject_class->get_property = vips_object_get_property;
197 
198 	vobject_class->nickname = "similarity";
199 	vobject_class->description = _( "similarity transform of an image" );
200 
201 	VIPS_ARG_DOUBLE( class, "scale", 3,
202 		_( "Scale" ),
203 		_( "Scale by this factor" ),
204 		VIPS_ARGUMENT_OPTIONAL_INPUT,
205 		G_STRUCT_OFFSET( VipsSimilarity, scale ),
206 		0, 10000000, 1 );
207 
208 	VIPS_ARG_DOUBLE( class, "angle", 4,
209 		_( "Angle" ),
210 		_( "Rotate anticlockwise by this many degrees" ),
211 		VIPS_ARGUMENT_OPTIONAL_INPUT,
212 		G_STRUCT_OFFSET( VipsSimilarity, angle ),
213 		-10000000, 10000000, 0 );
214 
215 }
216 
217 static void
vips_similarity_init(VipsSimilarity * similarity)218 vips_similarity_init( VipsSimilarity *similarity )
219 {
220 }
221 
222 /**
223  * vips_similarity: (method)
224  * @in: input image
225  * @out: (out): output image
226  * @...: %NULL-terminated list of optional named arguments
227  *
228  * Optional arguments:
229  *
230  * * @scale: %gdouble, scale by this factor
231  * * @angle: %gdouble, rotate by this many degrees clockwise
232  * * @interpolate: #VipsInterpolate, interpolate pixels with this
233  * * @background: #VipsArrayDouble colour for new pixels
234  * * @idx: %gdouble, input horizontal offset
235  * * @idy: %gdouble, input vertical offset
236  * * @odx: %gdouble, output horizontal offset
237  * * @ody: %gdouble, output vertical offset
238  * * @ody: %gdouble, output vertical offset
239  *
240  * This operator calls vips_affine() for you, calculating the matrix for the
241  * affine transform from @scale and @angle. Other parameters are passed on to
242  * vips_affine() unaltered.
243  *
244  * See also: vips_affine(), #VipsInterpolate.
245  *
246  * Returns: 0 on success, -1 on error
247  */
248 int
vips_similarity(VipsImage * in,VipsImage ** out,...)249 vips_similarity( VipsImage *in, VipsImage **out, ... )
250 {
251 	va_list ap;
252 	int result;
253 
254 	va_start( ap, out );
255 	result = vips_call_split( "similarity", ap, in, out );
256 	va_end( ap );
257 
258 	return( result );
259 }
260 
261 typedef VipsSimilarityBase VipsRotate;
262 typedef VipsSimilarityBaseClass VipsRotateClass;
263 
264 G_DEFINE_TYPE( VipsRotate, vips_rotate, vips_similarity_base_get_type() );
265 
266 static void
vips_rotate_class_init(VipsRotateClass * class)267 vips_rotate_class_init( VipsRotateClass *class )
268 {
269 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
270 	VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
271 
272 	gobject_class->set_property = vips_object_set_property;
273 	gobject_class->get_property = vips_object_get_property;
274 
275 	vobject_class->nickname = "rotate";
276 	vobject_class->description =
277 		_( "rotate an image by a number of degrees" );
278 
279 	VIPS_ARG_DOUBLE( class, "angle", 4,
280 		_( "Angle" ),
281 		_( "Rotate anticlockwise by this many degrees" ),
282 		VIPS_ARGUMENT_REQUIRED_INPUT,
283 		G_STRUCT_OFFSET( VipsSimilarity, angle ),
284 		-10000000, 10000000, 0 );
285 
286 }
287 
288 static void
vips_rotate_init(VipsRotate * rotate)289 vips_rotate_init( VipsRotate *rotate )
290 {
291 }
292 
293 /**
294  * vips_rotate: (method)
295  * @in: input image
296  * @out: (out): output image
297  * @angle: %gdouble, rotate by this many degrees clockwise
298  * @...: %NULL-terminated list of optional named arguments
299  *
300  * Optional arguments:
301  *
302  * * @interpolate: #VipsInterpolate, interpolate pixels with this
303  * * @background: #VipsArrayDouble colour for new pixels
304  * * @idx: %gdouble, input horizontal offset
305  * * @idy: %gdouble, input vertical offset
306  * * @odx: %gdouble, output horizontal offset
307  * * @ody: %gdouble, output vertical offset
308  * * @ody: %gdouble, output vertical offset
309  *
310  * This operator calls vips_affine() for you, calculating the matrix for the
311  * affine transform from @scale and @angle. Other parameters are passed on to
312  * vips_affine() unaltered.
313  *
314  * See also: vips_affine(), #VipsInterpolate.
315  *
316  * Returns: 0 on success, -1 on error
317  */
318 int
vips_rotate(VipsImage * in,VipsImage ** out,double angle,...)319 vips_rotate( VipsImage *in, VipsImage **out, double angle, ... )
320 {
321 	va_list ap;
322 	int result;
323 
324 	va_start( ap, angle );
325 	result = vips_call_split( "rotate", ap, in, out, angle );
326 	va_end( ap );
327 
328 	return( result );
329 }
330