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