1 /* rotate by 0/90/180/270 degrees
2  *
3  * Copyright: 1991, N. Dessipris
4  * Written on: 28/10/91
5  * Updated on: 2/4/92, J.Cupitt
6  * 	bugs in im_la90rot fixed, now works for any type.
7  * 19/7/93 JC
8  *	- IM_CODING_LABQ allowed now
9  * 15/11/94 JC
10  *	- name changed
11  *	- memory leaks fixed
12  * 8/2/95 JC
13  *	- oops! memory allocation problem fixed
14  * 18/5/95 JC
15  * 	- IM_MAXLINES increased
16  * 13/8/96 JC
17  *	- rewritten for partials
18  * 6/11/02 JC
19  *	- speed-up ... replace memcpy() with a loop for small pixels
20  * 14/4/04
21  *	- sets Xoffset / Yoffset
22  * 24/3/09
23  * 	- added IM_CODING_RAD support
24  * 1/2/10
25  * 	- cleanups
26  * 	- gtkdoc
27  * 4/11/11
28  * 	- rewrite as a class
29  * 7/3/17
30  * 	- added 90/180/270 convenience functions
31  */
32 
33 /*
34 
35     This file is part of VIPS.
36 
37     VIPS is free software; you can redistribute it and/or modify
38     it under the terms of the GNU Lesser General Public License as published by
39     the Free Software Foundation; either version 2 of the License, or
40     (at your option) any later version.
41 
42     This program is distributed in the hope that it will be useful,
43     but WITHOUT ANY WARRANTY; without even the implied warranty of
44     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
45     GNU Lesser General Public License for more details.
46 
47     You should have received a copy of the GNU Lesser General Public License
48     along with this program; if not, write to the Free Software
49     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
50     02110-1301  USA
51 
52  */
53 
54 /*
55 
56     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
57 
58  */
59 
60 /*
61 #define VIPS_DEBUG
62  */
63 
64 #ifdef HAVE_CONFIG_H
65 #include <config.h>
66 #endif /*HAVE_CONFIG_H*/
67 #include <vips/intl.h>
68 
69 #include <stdio.h>
70 #include <string.h>
71 #include <stdlib.h>
72 
73 #include <vips/vips.h>
74 #include <vips/internal.h>
75 #include <vips/debug.h>
76 
77 #include "pconversion.h"
78 
79 typedef struct _VipsRot {
80 	VipsConversion parent_instance;
81 
82 	/* The input image.
83 	 */
84 	VipsImage *in;
85 
86 	/* Rotate by ...
87 	 */
88 	VipsAngle angle;
89 
90 } VipsRot;
91 
92 typedef VipsConversionClass VipsRotClass;
93 
94 G_DEFINE_TYPE( VipsRot, vips_rot, VIPS_TYPE_CONVERSION );
95 
96 static int
vips_rot90_gen(VipsRegion * or,void * seq,void * a,void * b,gboolean * stop)97 vips_rot90_gen( VipsRegion *or, void *seq, void *a, void *b,
98 	gboolean *stop )
99 {
100 	VipsRegion *ir = (VipsRegion *) seq;
101 	VipsImage *in = (VipsImage *) a;
102 
103 	/* Output area.
104 	 */
105 	VipsRect *r = &or->valid;
106 	int le = r->left;
107 	int ri = VIPS_RECT_RIGHT(r);
108 	int to = r->top;
109 	int bo = VIPS_RECT_BOTTOM(r);
110 
111 	int x, y, i;
112 
113 	/* Pixel geometry.
114 	 */
115 	int ps, ls;
116 
117 	/* Find the area of the input image we need.
118 	 */
119 	VipsRect need;
120 
121 	need.left = to;
122 	need.top = in->Ysize - ri;
123 	need.width = r->height;
124 	need.height = r->width;
125 	if( vips_region_prepare( ir, &need ) )
126 		return( -1 );
127 
128 	/* Find PEL size and line skip for ir.
129 	 */
130 	ps = VIPS_IMAGE_SIZEOF_PEL( in );
131 	ls = VIPS_REGION_LSKIP( ir );
132 
133 	/* Rotate the bit we now have.
134 	 */
135 	for( y = to; y < bo; y++ ) {
136 		/* Start of this output line.
137 		 */
138 		VipsPel *q = VIPS_REGION_ADDR( or, le, y );
139 
140 		/* Corresponding position in ir.
141 		 */
142 		VipsPel *p = VIPS_REGION_ADDR( ir,
143 			need.left + y - to,
144 			need.top + need.height - 1 );
145 
146 		for( x = le; x < ri; x++ ) {
147 			for( i = 0; i < ps; i++ )
148 				q[i] = p[i];
149 
150 			q += ps;
151 			p -= ls;
152 		}
153 	}
154 
155 	return( 0 );
156 }
157 
158 static int
vips_rot180_gen(VipsRegion * or,void * seq,void * a,void * b,gboolean * stop)159 vips_rot180_gen( VipsRegion *or, void *seq, void *a, void *b,
160 	gboolean *stop )
161 {
162 	VipsRegion *ir = (VipsRegion *) seq;
163 	VipsImage *in = (VipsImage *) a;
164 
165 	/* Output area.
166 	 */
167 	VipsRect *r = &or->valid;
168 	int le = r->left;
169 	int ri = VIPS_RECT_RIGHT(r);
170 	int to = r->top;
171 	int bo = VIPS_RECT_BOTTOM(r);
172 
173 	int x, y;
174 
175 	/* Pixel geometry.
176 	 */
177 	int ps;
178 
179 	/* Find the area of the input image we need.
180 	 */
181 	VipsRect need;
182 
183 	need.left = in->Xsize - ri;
184 	need.top = in->Ysize - bo;
185 	need.width = r->width;
186 	need.height = r->height;
187 	if( vips_region_prepare( ir, &need ) )
188 		return( -1 );
189 
190 	/* Find PEL size and line skip for ir.
191 	 */
192 	ps = VIPS_IMAGE_SIZEOF_PEL( in );
193 
194 	/* Rotate the bit we now have.
195 	 */
196 	for( y = to; y < bo; y++ ) {
197 		/* Start of this output line.
198 		 */
199 		VipsPel *q = VIPS_REGION_ADDR( or, le, y );
200 
201 		/* Corresponding position in ir.
202 		 */
203 		VipsPel *p = VIPS_REGION_ADDR( ir,
204 			need.left + need.width - 1,
205 			need.top + need.height - (y - to) - 1 );
206 
207 		/* Blap across!
208 		 */
209 		for( x = le; x < ri; x++ ) {
210 			memcpy( q, p, ps );
211 			q += ps;
212 			p -= ps;
213 		}
214 	}
215 
216 	return( 0 );
217 }
218 
219 static int
vips_rot270_gen(VipsRegion * or,void * seq,void * a,void * b,gboolean * stop)220 vips_rot270_gen( VipsRegion *or, void *seq, void *a, void *b,
221 	gboolean *stop )
222 {
223 	VipsRegion *ir = (VipsRegion *) seq;
224 	VipsImage *in = (VipsImage *) a;
225 
226 	/* Output area.
227 	 */
228 	VipsRect *r = &or->valid;
229 	int le = r->left;
230 	int ri = VIPS_RECT_RIGHT(r);
231 	int to = r->top;
232 	int bo = VIPS_RECT_BOTTOM(r);
233 
234 	int x, y, i;
235 
236 	/* Pixel geometry.
237 	 */
238 	int ps, ls;
239 
240 	/* Find the area of the input image we need.
241 	 */
242 	VipsRect need;
243 
244 	need.left = in->Xsize - bo;
245 	need.top = le;
246 	need.width = r->height;
247 	need.height = r->width;
248 	if( vips_region_prepare( ir, &need ) )
249 		return( -1 );
250 
251 	/* Find PEL size and line skip for ir.
252 	 */
253 	ps = VIPS_IMAGE_SIZEOF_PEL( in );
254 	ls = VIPS_REGION_LSKIP( ir );
255 
256 	/* Rotate the bit we now have.
257 	 */
258 	for( y = to; y < bo; y++ ) {
259 		/* Start of this output line.
260 		 */
261 		VipsPel *q = VIPS_REGION_ADDR( or, le, y );
262 
263 		/* Corresponding position in ir.
264 		 */
265 		VipsPel *p = VIPS_REGION_ADDR( ir,
266 			need.left + need.width - (y - to) - 1,
267 			need.top );
268 
269 		for( x = le; x < ri; x++ ) {
270 			for( i = 0; i < ps; i++ )
271 				q[i] = p[i];
272 
273 			q += ps;
274 			p += ls;
275 		}
276 	}
277 
278 	return( 0 );
279 }
280 
281 static int
vips_rot_build(VipsObject * object)282 vips_rot_build( VipsObject *object )
283 {
284 	VipsConversion *conversion = VIPS_CONVERSION( object );
285 	VipsRot *rot = (VipsRot *) object;
286 
287 	VipsGenerateFn generate_fn;
288 	VipsDemandStyle hint;
289 
290 	if( VIPS_OBJECT_CLASS( vips_rot_parent_class )->build( object ) )
291 		return( -1 );
292 
293 	if( rot->angle == VIPS_ANGLE_D0 )
294 		return( vips_image_write( rot->in, conversion->out ) );
295 
296 	if( vips_image_pio_input( rot->in ) )
297 		return( -1 );
298 
299 	hint = rot->angle == VIPS_ANGLE_D180 ?
300 		VIPS_DEMAND_STYLE_THINSTRIP :
301 		VIPS_DEMAND_STYLE_SMALLTILE;
302 
303 	if( vips_image_pipelinev( conversion->out, hint, rot->in, NULL ) )
304 		return( -1 );
305 
306 	switch( rot->angle ) {
307 	case VIPS_ANGLE_D90:
308 		generate_fn = vips_rot90_gen;
309 		conversion->out->Xsize = rot->in->Ysize;
310 		conversion->out->Ysize = rot->in->Xsize;
311 		conversion->out->Xoffset = rot->in->Ysize;
312 		conversion->out->Yoffset = 0;
313 		break;
314 
315 	case VIPS_ANGLE_D180:
316 		generate_fn = vips_rot180_gen;
317 		conversion->out->Xoffset = rot->in->Xsize;
318 		conversion->out->Yoffset = rot->in->Ysize;
319 		break;
320 
321 	case VIPS_ANGLE_D270:
322 		generate_fn = vips_rot270_gen;
323 		conversion->out->Xsize = rot->in->Ysize;
324 		conversion->out->Ysize = rot->in->Xsize;
325 		conversion->out->Xoffset = 0;
326 		conversion->out->Yoffset = rot->in->Xsize;
327 		break;
328 
329 	default:
330 		g_assert_not_reached();
331 
332 		/* Stop compiler warnings.
333 		 */
334 		generate_fn = NULL;
335 	}
336 
337 	if( vips_image_generate( conversion->out,
338 		vips_start_one, generate_fn, vips_stop_one,
339 		rot->in, rot ) )
340 		return( -1 );
341 
342 	return( 0 );
343 }
344 
345 static void
vips_rot_class_init(VipsRotClass * class)346 vips_rot_class_init( VipsRotClass *class )
347 {
348 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
349 	VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
350 
351 	VIPS_DEBUG_MSG( "vips_rot_class_init\n" );
352 
353 	gobject_class->set_property = vips_object_set_property;
354 	gobject_class->get_property = vips_object_get_property;
355 
356 	vobject_class->nickname = "rot";
357 	vobject_class->description = _( "rotate an image" );
358 	vobject_class->build = vips_rot_build;
359 
360 	VIPS_ARG_IMAGE( class, "in", 1,
361 		_( "Input" ),
362 		_( "Input image" ),
363 		VIPS_ARGUMENT_REQUIRED_INPUT,
364 		G_STRUCT_OFFSET( VipsRot, in ) );
365 
366 	VIPS_ARG_ENUM( class, "angle", 6,
367 		_( "Angle" ),
368 		_( "Angle to rotate image" ),
369 		VIPS_ARGUMENT_REQUIRED_INPUT,
370 		G_STRUCT_OFFSET( VipsRot, angle ),
371 		VIPS_TYPE_ANGLE, VIPS_ANGLE_D90 );
372 }
373 
374 static void
vips_rot_init(VipsRot * rot)375 vips_rot_init( VipsRot *rot )
376 {
377 }
378 
379 static int
vips_rotv(VipsImage * in,VipsImage ** out,VipsAngle angle,va_list ap)380 vips_rotv( VipsImage *in, VipsImage **out, VipsAngle angle, va_list ap )
381 {
382 	return( vips_call_split( "rot", ap, in, out, angle ) );
383 }
384 
385 /**
386  * vips_rot: (method)
387  * @in: input image
388  * @out: (out): output image
389  * @angle: rotation angle
390  * @...: %NULL-terminated list of optional named arguments
391  *
392  * Rotate @in by a multiple of 90 degrees.
393  *
394  * Use vips_similarity() to rotate by an arbitary angle. vips_rot45() is
395  * useful for rotating convolution masks by 45 degrees.
396  *
397  * See also: vips_flip(), vips_similarity(), vips_rot45().
398  *
399  * Returns: 0 on success, -1 on error
400  */
401 int
vips_rot(VipsImage * in,VipsImage ** out,VipsAngle angle,...)402 vips_rot( VipsImage *in, VipsImage **out, VipsAngle angle, ... )
403 {
404 	va_list ap;
405 	int result;
406 
407 	va_start( ap, angle );
408 	result = vips_rotv( in, out, angle, ap );
409 	va_end( ap );
410 
411 	return( result );
412 }
413 
414 /**
415  * vips_rot90:
416  * @in: input image
417  * @out: output image
418  * @...: %NULL-terminated list of optional named arguments
419  *
420  * Rotate @in by 90 degress clockwise. A convenience function over vips_rot().
421  *
422  * See also: vips_rot().
423  *
424  * Returns: 0 on success, -1 on error
425  */
426 int
vips_rot90(VipsImage * in,VipsImage ** out,...)427 vips_rot90( VipsImage *in, VipsImage **out, ... )
428 {
429 	va_list ap;
430 	int result;
431 
432 	va_start( ap, out );
433 	result = vips_rotv( in, out, VIPS_ANGLE_D90, ap );
434 	va_end( ap );
435 
436 	return( result );
437 }
438 
439 /**
440  * vips_rot180: (method)
441  * @in: input image
442  * @out: (out): output image
443  * @...: %NULL-terminated list of optional named arguments
444  *
445  * Rotate @in by 180 degress. A convenience function over vips_rot().
446  *
447  * See also: vips_rot().
448  *
449  * Returns: 0 on success, -1 on error
450  */
451 int
vips_rot180(VipsImage * in,VipsImage ** out,...)452 vips_rot180( VipsImage *in, VipsImage **out, ... )
453 {
454 	va_list ap;
455 	int result;
456 
457 	va_start( ap, out );
458 	result = vips_rotv( in, out, VIPS_ANGLE_D180, ap );
459 	va_end( ap );
460 
461 	return( result );
462 }
463 
464 /**
465  * vips_rot270: (method)
466  * @in: input image
467  * @out: (out): output image
468  * @...: %NULL-terminated list of optional named arguments
469  *
470  * Rotate @in by 270 degress clockwise. A convenience function over vips_rot().
471  *
472  * See also: vips_rot().
473  *
474  * Returns: 0 on success, -1 on error
475  */
476 int
vips_rot270(VipsImage * in,VipsImage ** out,...)477 vips_rot270( VipsImage *in, VipsImage **out, ... )
478 {
479 	va_list ap;
480 	int result;
481 
482 	va_start( ap, out );
483 	result = vips_rotv( in, out, VIPS_ANGLE_D270, ap );
484 	va_end( ap );
485 
486 	return( result );
487 }
488