1 /* 'lossless' 45 degree rotate ... odd-sized square images only
2  *
3  * Author: N. Dessipris (Copyright, N. Dessipris 1991)
4  * Written on: 08/05/1991
5  * Modified on: 28/05/1991
6  * 12/10/95 JC
7  *	- small revisions, needs rewriting really
8  * 7/8/96 JC
9  *	- absolutely foul desp code revised
10  *	- many bugs and mem leaks fixed
11  * 1/3/99 JC
12  *	- oops, fns were not preserving scale and offset
13  * 1/12/10
14  * 	- allow any size mask for the 90 degree rot45ates by using im_rot4590().
15  * 12/10/13
16  * 	- rewritten as a class
17  */
18 
19 /*
20 
21     This file is part of VIPS.
22 
23     VIPS is free software; you can redistribute it and/or modify
24     it under the terms of the GNU Lesser General Public License as published by
25     the Free Software Foundation; either version 2 of the License, or
26     (at your option) any later version.
27 
28     This program is distributed in the hope that it will be useful,
29     but WITHOUT ANY WARRANTY; without even the implied warranty of
30     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31     GNU Lesser General Public License for more details.
32 
33     You should have received a copy of the GNU Lesser General Public License
34     along with this program; if not, write to the Free Software
35     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
36     02110-1301  USA
37 
38  */
39 
40 /*
41 
42     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
43 
44  */
45 
46 /*
47 #define VIPS_DEBUG
48  */
49 
50 #ifdef HAVE_CONFIG_H
51 #include <config.h>
52 #endif /*HAVE_CONFIG_H*/
53 #include <vips/intl.h>
54 
55 #include <stdio.h>
56 #include <string.h>
57 #include <stdlib.h>
58 
59 #include <vips/vips.h>
60 #include <vips/internal.h>
61 #include <vips/debug.h>
62 
63 #include "pconversion.h"
64 
65 typedef struct _VipsRot45 {
66 	VipsConversion parent_instance;
67 
68 	/* The input image.
69 	 */
70 	VipsImage *in;
71 
72 	/* Rotate by ...
73 	 */
74 	VipsAngle45 angle;
75 
76 } VipsRot45;
77 
78 typedef VipsConversionClass VipsRot45Class;
79 
80 G_DEFINE_TYPE( VipsRot45, vips_rot45, VIPS_TYPE_CONVERSION );
81 
82 #define COPY( Q, P ) { \
83 	VipsPel *q = (Q); \
84 	VipsPel *p = (P); \
85 	int b;\
86 	\
87 	for( b = 0; b < ps; b++ )\
88 		q[b] = p[b];\
89 }
90 
91 #define ASSIGN( Xout, Yout, Xin, Yin ) \
92 	COPY( VIPS_IMAGE_ADDR( out, Xout, Yout ), \
93 		VIPS_IMAGE_ADDR( in, Xin, Yin ) )
94 
95 #define POINT_TO_TEMP( q, Xin, Yin ) \
96 	COPY( q, VIPS_IMAGE_ADDR( in, Xin, Yin ) )
97 
98 #define TEMP_TO_POINT( Xout, Yout, p ) \
99 	COPY( VIPS_IMAGE_ADDR( out, Xout, Yout ), p )
100 
101 /* This can work inplace, ie. in == out is allowed.
102  */
103 static void
vips_rot45_rot45(VipsImage * out,VipsImage * in)104 vips_rot45_rot45( VipsImage *out, VipsImage *in )
105 {
106 	size_t ps = VIPS_IMAGE_SIZEOF_PEL( in );
107 	VipsPel *temp = VIPS_ARRAY( in, ps, VipsPel );
108 	int size = in->Xsize;
109 	int size_2 = size / 2;
110 
111 	int x, y;
112 
113 	g_assert( in->Xsize == in->Ysize );
114 	g_assert( out->Xsize == out->Ysize );
115 	g_assert( in->Xsize == out->Xsize );
116 	g_assert( in->Xsize % 2 == 1 );
117 
118 	/* Split the square into 8 triangles. Loop over the top-left one,
119 	 * reflect to index the others.
120 	 *
121 	 * 	1 1 2 2 3
122 	 * 	8 1 2 3 3
123 	 * 	8 8 x 4 4
124 	 * 	7 7 6 5 4
125 	 * 	7 6 6 5 5
126 	 *
127 	 * do the centre separately.
128 	 */
129 
130 	for( y = 0; y < size_2; y++ )
131 		for( x = y; x < size_2; x++ ) {
132 			/* Save 1, it goes into 2 at the end.
133 			 */
134 			POINT_TO_TEMP( temp, x, y );
135 
136 			/* Fill 1 from 8.
137 			 */
138 			ASSIGN( x, y,
139 				y, size_2 - (x - y) );
140 
141 			/* 8 from 7.
142 			 */
143 			ASSIGN( y, size_2 - (x - y),
144 				y, (size - 1) - x );
145 
146 			/* 7 from 6.
147 			 */
148 			ASSIGN( y, (size - 1) - x,
149 				size_2 - (x - y), (size - 1) - y );
150 
151 			/* 6 from 5.
152 			 */
153 			ASSIGN( size_2 - (x - y), (size - 1) - y,
154 				(size - 1) - x, (size - 1) - y );
155 
156 			/* 5 from 4.
157 			 */
158 			ASSIGN( (size - 1) - x, (size - 1) - y,
159 				(size - 1) - y, (x - y) + size_2 );
160 
161 			/* 4 from 3.
162 			 */
163 			ASSIGN( (size - 1) - y, (x - y) + size_2,
164 				(size - 1) - y, x );
165 
166 			/* 3 from 2.
167 			 */
168 			ASSIGN( (size - 1) - y, x,
169 				(x - y) + size_2, y );
170 
171 			/* 2 from saved 1.
172 			 */
173 			TEMP_TO_POINT( (x - y) + size_2, y, temp );
174 		}
175 
176 	/* Centre.
177 	 */
178 	ASSIGN( size_2, size_2, size_2, size_2 );
179 }
180 
181 static int
vips_rot45_build(VipsObject * object)182 vips_rot45_build( VipsObject *object )
183 {
184 	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
185 	VipsConversion *conversion = VIPS_CONVERSION( object );
186 	VipsRot45 *rot45 = (VipsRot45 *) object;
187 	VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 );
188 
189 	VipsImage *in;
190 
191 	if( VIPS_OBJECT_CLASS( vips_rot45_parent_class )->build( object ) )
192 		return( -1 );
193 
194 	if( vips_check_oddsquare( class->nickname, rot45->in ) )
195 		return( -1 );
196 
197 	if( rot45->angle == VIPS_ANGLE45_D0 )
198 		return( vips_image_write( rot45->in, conversion->out ) );
199 
200 	if( !(t[1] = vips_image_copy_memory( rot45->in )) )
201 		return( -1 );
202 	in = t[1];
203 
204 	t[0] = vips_image_new_memory();
205 	if( vips_image_pipelinev( t[0],
206 		VIPS_DEMAND_STYLE_ANY, rot45->in, NULL ) )
207 		return( -1 );
208 	if( vips_image_write_prepare( t[0] ) )
209 		return( -1 );
210 
211 	switch( rot45->angle ) {
212 	case VIPS_ANGLE45_D315:
213 		vips_rot45_rot45( t[0], in );
214 		in = t[0];
215 
216 	case VIPS_ANGLE45_D270:
217 		vips_rot45_rot45( t[0], in );
218 		in = t[0];
219 
220 	case VIPS_ANGLE45_D225:
221 		vips_rot45_rot45( t[0], in );
222 		in = t[0];
223 
224 	case VIPS_ANGLE45_D180:
225 		vips_rot45_rot45( t[0], in );
226 		in = t[0];
227 
228 	case VIPS_ANGLE45_D135:
229 		vips_rot45_rot45( t[0], in );
230 		in = t[0];
231 
232 	case VIPS_ANGLE45_D90:
233 		vips_rot45_rot45( t[0], in );
234 		in = t[0];
235 
236 	case VIPS_ANGLE45_D45:
237 		vips_rot45_rot45( t[0], in );
238 		in = t[0];
239 		break;
240 
241 	default:
242 		g_assert_not_reached();
243 	}
244 
245 	if( vips_image_write( in, conversion->out ) )
246 		return( -1 );
247 
248 	return( 0 );
249 }
250 
251 static void
vips_rot45_class_init(VipsRot45Class * class)252 vips_rot45_class_init( VipsRot45Class *class )
253 {
254 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
255 	VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
256 
257 	VIPS_DEBUG_MSG( "vips_rot45_class_init\n" );
258 
259 	gobject_class->set_property = vips_object_set_property;
260 	gobject_class->get_property = vips_object_get_property;
261 
262 	vobject_class->nickname = "rot45";
263 	vobject_class->description = _( "rotate an image" );
264 	vobject_class->build = vips_rot45_build;
265 
266 	VIPS_ARG_IMAGE( class, "in", 1,
267 		_( "Input" ),
268 		_( "Input image" ),
269 		VIPS_ARGUMENT_REQUIRED_INPUT,
270 		G_STRUCT_OFFSET( VipsRot45, in ) );
271 
272 	VIPS_ARG_ENUM( class, "angle", 6,
273 		_( "Angle" ),
274 		_( "Angle to rotate image" ),
275 		VIPS_ARGUMENT_OPTIONAL_INPUT,
276 		G_STRUCT_OFFSET( VipsRot45, angle ),
277 		VIPS_TYPE_ANGLE45, VIPS_ANGLE45_D45 );
278 }
279 
280 static void
vips_rot45_init(VipsRot45 * rot45)281 vips_rot45_init( VipsRot45 *rot45 )
282 {
283 	rot45->angle = VIPS_ANGLE45_D45;
284 }
285 
286 /**
287  * vips_rot45: (method)
288  * @in: input image
289  * @out: (out): output image
290  * @...: %NULL-terminated list of optional named arguments
291  *
292  * Optional arguments:
293  *
294  * * @angle: #VipsAngle45 rotation angle
295  *
296  * Rotate @in by a multiple of 45 degrees. Odd-length sides and square images
297  * only.
298  *
299  * This operation is useful for rotating convolution masks. Use
300  * vips_similarity() to rotate images by arbitrary angles.
301  *
302  * See also: vips_rot(), vips_similarity().
303  *
304  * Returns: 0 on success, -1 on error
305  */
306 int
vips_rot45(VipsImage * in,VipsImage ** out,...)307 vips_rot45( VipsImage *in, VipsImage **out, ... )
308 {
309 	va_list ap;
310 	int result;
311 
312 	va_start( ap, out );
313 	result = vips_call_split( "rot45", ap, in, out );
314 	va_end( ap );
315 
316 	return( result );
317 }
318