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