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