1 /* affine transform with a supplied interpolator.
2  *
3  * Copyright N. Dessipris
4  * Written on: 01/11/1991
5  * Modified on: 12/3/92 JC
6  *	- rounding error in interpolation routine fixed
7  *	- test for scale=1, angle=0 case fixed
8  *	- clipping of output removed: redundant
9  *	- various little tidies
10  *	- problems remain with scale>20, size<10
11  *
12  * Re-written on: 20/08/92, J.Ph Laurent
13  *
14  * 21/02/93, JC
15  *	- speed-ups
16  * 	- simplifications
17  *	- im_similarity now calculates a window and calls this routine
18  * 6/7/93 JC
19  *	- rewritten for partials
20  *	- ANSIfied
21  *	- now rotates any non-complex type
22  * 3/6/94 JC
23  *	- C revised in bug search
24  * 9/6/94 JC
25  *	- im_prepare() was preparing too small an area! oops
26  * 22/5/95 JC
27  *	- added code to detect all-black output area case - helps lazy ip
28  * 3/7/95 JC
29  *	- IM_CODING_LABQ handling moved to here
30  * 31/7/97 JC
31  * 	- dx/dy sign reversed to be less confusing ... now follows comment at
32  * 	  top ... ax - by + dx etc.
33  *	- tiny speed up, replaced the *++ on interpolation with [z]
34  *	- im_similarity() moved in here
35  *	- args swapped: was whxy, now xywh
36  *	- didn't agree with dispatch fns before :(
37  * 3/3/98 JC
38  *	- im_demand_hint() added
39  * 20/12/99 JC
40  *	- im_affine() made from im_similarity_area()
41  *	- transform stuff cleaned up a bit
42  * 14/4/01 JC
43  *	- oops, invert_point() had a rounding problem
44  * 23/2/02 JC
45  *	- pre-calculate interpolation matricies
46  *	- integer interpolation for int8/16 types, double for
47  *	  int32/float/double
48  *	- faster transformation
49  * 15/8/02 JC
50  *	- records Xoffset/Yoffset
51  * 14/4/04
52  *	- rounding, clipping and transforming revised, now pixel-perfect (or
53  *	  better than gimp, anyway)
54  * 22/6/05
55  *	- all revised again, simpler and more reliable now
56  * 30/3/06
57  * 	- gah, still an occasional clipping problem
58  * 12/7/06
59  * 	- still more tweaking, gah again
60  * 7/10/06
61  * 	- set THINSTRIP for no-rotate affines
62  * 20/10/08
63  * 	- version with interpolate parameter, from im_affine()
64  * 30/10/08
65  * 	- allow complex image types
66  * 4/11/08
67  * 	- take an interpolator as a param
68  * 	- replace im_affine with this, provide an im_affine() compat wrapper
69  * 	- break transform stuff out to transform.c
70  * 	- revise clipping / transform stuff, again
71  * 	- now do corner rather than centre: this way the identity transform
72  * 	  returns the input exactly
73  * 12/8/10
74  * 	- revise window_size / window_offset stuff again, see also
75  * 	  interpolate.c
76  * 2/2/11
77  * 	- gtk-doc
78  * 14/12/12
79  * 	- redone as a class
80  * 	- added input space translation
81  * 22/1/14
82  * 	- auto RAD decode
83  * 1/8/14
84  * 	- revise transform ... again
85  * 	- see new stress test in nip2/test/extras
86  * 7/11/17
87  * 	- add "extend" param
88  * 	- add "background" parameter
89  * 	- better clipping means we have no jaggies on edges
90  * 	- premultiply alpha
91  * 18/5/20
92  * 	- add "premultiplied" flag
93  */
94 
95 /*
96 
97     This file is part of VIPS.
98 
99     VIPS is free software; you can redistribute it and/or modify
100     it under the terms of the GNU Lesser General Public License as published by
101     the Free Software Foundation; either version 2 of the License, or
102     (at your option) any later version.
103 
104     This program is distributed in the hope that it will be useful,
105     but WITHOUT ANY WARRANTY; without even the implied warranty of
106     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
107     GNU Lesser General Public License for more details.
108 
109     You should have received a copy of the GNU Lesser General Public License
110     along with this program; if not, write to the Free Software
111     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
112     02110-1301  USA
113 
114  */
115 
116 /*
117 
118     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
119 
120  */
121 
122 /*
123 #define DEBUG_VERBOSE
124 #define DEBUG
125 #define VIPS_DEBUG
126  */
127 
128 #ifdef HAVE_CONFIG_H
129 #include <config.h>
130 #endif /*HAVE_CONFIG_H*/
131 #include <vips/intl.h>
132 
133 #include <stdio.h>
134 #include <stdlib.h>
135 #include <string.h>
136 #include <math.h>
137 #include <limits.h>
138 
139 #include <vips/vips.h>
140 #include <vips/debug.h>
141 #include <vips/internal.h>
142 #include <vips/transform.h>
143 
144 #include "presample.h"
145 
146 typedef struct _VipsAffine {
147 	VipsResample parent_instance;
148 
149 	VipsArea *matrix;
150 	VipsInterpolate *interpolate;
151 	VipsArea *oarea;
152 	double odx;
153 	double ody;
154 	double idx;
155 	double idy;
156 
157 	VipsTransformation trn;
158 
159 	/* How to generate extra edge pixels.
160 	 */
161 	VipsExtend extend;
162 
163 	/* Background colour.
164 	 */
165 	VipsArrayDouble *background;
166 
167 	/* The [double] converted to the input image format.
168 	 */
169 	VipsPel *ink;
170 
171 	/* True if the input is already premultiplied (and we don't need to).
172 	 */
173 	gboolean premultiplied;
174 
175 } VipsAffine;
176 
177 typedef VipsResampleClass VipsAffineClass;
178 
179 G_DEFINE_TYPE( VipsAffine, vips_affine, VIPS_TYPE_RESAMPLE );
180 
181 /* We have five (!!) coordinate systems. Working forward through them, these
182  * are:
183  *
184  * 1. The original input image. iarea is defined on this image.
185  *
186  * 2. This is embedded in a larger image to provide borders for the
187  * interpolator. window_offset and window_size control the embedding.
188  * These are the coordinates we pass to VIPS_REGION_ADDR()/
189  * vips_region_prepare() and the interpolator.
190  *
191  * The borders are sized by the interpolator's window_size property and offset
192  * by the interpolator's window_offset property. For example,
193  * for bilinear (window_size 2, window_offset 0) we add a single line
194  * of extra pixels along the bottom and right (window_size - 1). For
195  * bicubic (window_size 4, window_offset 1) we add a single line top and left
196  * (window_offset), and two lines bottom and right (window_size - 1 -
197  * window_offset).
198  *
199  * 3. We need point (0, 0) in (1) to be at (0, 0) for the transformation. So
200  * shift everything up and left to make the displaced input image. This is the
201  * space that the transformation maps from, and can have negative pixels
202  * (up and left of the image, for interpolation). iarea works here too.
203  *
204  * 4. Output transform space. This is the where the transform maps to. Pixels
205  * can be negative, since a rotated image can go up and left of the origin.
206  *
207  * 5. Output image space. This is the wh of the xywh passed to vips_affine()
208  * below. These are the coordinates we pass to VIPS_REGION_ADDR() for the
209  * output image, and that affinei_gen() is asked for.
210  */
211 
212 static int
vips_affine_gen(VipsRegion * or,void * seq,void * a,void * b,gboolean * stop)213 vips_affine_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
214 {
215 	VipsRegion *ir = (VipsRegion *) seq;
216 	const VipsAffine *affine = (VipsAffine *) b;
217 	const VipsImage *in = (VipsImage *) a;
218 	const int window_size =
219 		vips_interpolate_get_window_size( affine->interpolate );
220 	const int window_offset =
221 		vips_interpolate_get_window_offset( affine->interpolate );
222 	const VipsInterpolateMethod interpolate =
223 		vips_interpolate_get_method( affine->interpolate );
224 
225 	/* Area we generate in the output image.
226 	 */
227 	const VipsRect *r = &or->valid;
228 	const int le = r->left;
229 	const int ri = VIPS_RECT_RIGHT( r );
230 	const int to = r->top;
231 	const int bo = VIPS_RECT_BOTTOM( r );
232 
233 	const VipsRect *iarea = &affine->trn.iarea;
234 	const VipsRect *oarea = &affine->trn.oarea;
235 
236 	int ps = VIPS_IMAGE_SIZEOF_PEL( in );
237 	int x, y, z;
238 
239 	VipsRect image, want, need, clipped;
240 
241 #ifdef DEBUG_VERBOSE
242 	printf( "vips_affine_gen: "
243 		"generating left=%d, top=%d, width=%d, height=%d\n",
244 		r->left,
245 		r->top,
246 		r->width,
247 		r->height );
248 #endif /*DEBUG_VERBOSE*/
249 
250 	/* We are generating this chunk of the transformed image. This takes
251 	 * us to space 4.
252 	 */
253 	want = *r;
254 	want.left += oarea->left;
255 	want.top += oarea->top;
256 
257 	/* Find the area of the input image we need. This takes us to space 3.
258 	 */
259 	vips__transform_invert_rect( &affine->trn, &want, &need );
260 
261 	/* That does round-to-nearest, because it has to stop rounding errors
262 	 * growing images unexpectedly. We need round-down, so we must
263 	 * add half a pixel along the left and top. But we are int :( so add 1
264 	 * pixel.
265 	 *
266 	 * Add an extra line along the right and bottom as well, for rounding.
267 	 */
268 	vips_rect_marginadjust( &need, 1 );
269 
270 	/* We need to fetch a larger area for the interpolator.
271 	 */
272 	need.left -= window_offset;
273 	need.top -= window_offset;
274 	need.width += window_size - 1;
275 	need.height += window_size - 1;
276 
277 	/* Now go to space 2, the expanded input image. This is the one we
278 	 * read pixels from.
279 	 */
280 	need.left += window_offset;
281 	need.top += window_offset;
282 
283 	/* Clip against the size of (2).
284 	 */
285 	image.left = 0;
286 	image.top = 0;
287 	image.width = in->Xsize;
288 	image.height = in->Ysize;
289 	vips_rect_intersectrect( &need, &image, &clipped );
290 
291 #ifdef DEBUG_VERBOSE
292 	printf( "vips_affine_gen: "
293 		"preparing left=%d, top=%d, width=%d, height=%d\n",
294 		clipped.left,
295 		clipped.top,
296 		clipped.width,
297 		clipped.height );
298 #endif /*DEBUG_VERBOSE*/
299 
300 	if( vips_rect_isempty( &clipped ) ) {
301 		vips_region_paint_pel( or, r, affine->ink );
302 		return( 0 );
303 	}
304 	if( vips_region_prepare( ir, &clipped ) )
305 		return( -1 );
306 
307 	VIPS_GATE_START( "vips_affine_gen: work" );
308 
309 	/* Resample! x/y loop over pixels in the output image (5).
310 	 */
311 	for( y = to; y < bo; y++ ) {
312 		/* Input clipping rectangle. We offset this so we can clip in
313 		 * space 2.
314 		 */
315 		const int ile = iarea->left + window_offset;
316 		const int ito = iarea->top + window_offset;
317 		const int iri = ile + iarea->width;
318 		const int ibo = ito + iarea->height;
319 
320 		/* Derivative of matrix.
321 		 */
322 		const double ddx = affine->trn.ia;
323 		const double ddy = affine->trn.ic;
324 
325 		/* Continuous cods in transformed space.
326 		 */
327 		const double ox = le + oarea->left - affine->trn.odx;
328 		const double oy = y + oarea->top - affine->trn.ody;
329 
330 		/* Continuous cods in input space.
331 		 */
332 		double ix, iy;
333 
334 		VipsPel *q;
335 
336 		/* To (3).
337 		 */
338 		ix = affine->trn.ia * ox + affine->trn.ib * oy;
339 		iy = affine->trn.ic * ox + affine->trn.id * oy;
340 
341 		/* And the input offset in (3).
342 		 */
343 		ix -= affine->trn.idx;
344 		iy -= affine->trn.idy;
345 
346 		/* Finally to 2.
347 		 */
348 		ix += window_offset;
349 		iy += window_offset;
350 
351 		q = VIPS_REGION_ADDR( or, le, y );
352 
353 		for( x = le; x < ri; x++ ) {
354 			int fx, fy;
355 
356 			fx = VIPS_FLOOR( ix );
357 			fy = VIPS_FLOOR( iy );
358 
359 			/* Clip against iarea.
360 			 */
361 			if( fx >= ile &&
362 				fx <= iri &&
363 				fy >= ito &&
364 				fy <= ibo ) {
365 				/* Verify that we can read the whole stencil.
366 				 * With DEBUG on this will range-check.
367 				 */
368 				g_assert( VIPS_REGION_ADDR( ir,
369 					(int) ix - window_offset,
370 					(int) iy - window_offset ) );
371 				g_assert( VIPS_REGION_ADDR( ir,
372 					(int) ix - window_offset +
373 						window_size - 1,
374 					(int) iy - window_offset +
375 						window_size - 1 ) );
376 
377 				interpolate( affine->interpolate,
378 					q, ir, ix, iy );
379 			}
380 			else {
381 				/* Out of range: paint the background.
382 				 */
383 				for( z = 0; z < ps; z++ )
384 					q[z] = affine->ink[z];
385 			}
386 
387 			ix += ddx;
388 			iy += ddy;
389 			q += ps;
390 		}
391 	}
392 
393 	VIPS_GATE_STOP( "vips_affine_gen: work" );
394 
395 	VIPS_COUNT_PIXELS( or, "vips_affine_gen" );
396 
397 	return( 0 );
398 }
399 
400 static int
vips_affine_build(VipsObject * object)401 vips_affine_build( VipsObject *object )
402 {
403 	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
404 	VipsResample *resample = VIPS_RESAMPLE( object );
405 	VipsAffine *affine = (VipsAffine *) object;
406 	VipsImage **t = (VipsImage **) vips_object_local_array( object, 7 );
407 
408 	VipsImage *in;
409 	VipsDemandStyle hint;
410 	int window_size;
411 	int window_offset;
412 	double edge;
413 
414 	/* TRUE if we've premultiplied and need to unpremultiply.
415 	 */
416 	gboolean have_premultiplied;
417 	VipsBandFormat unpremultiplied_format;
418 
419 	if( VIPS_OBJECT_CLASS( vips_affine_parent_class )->build( object ) )
420 		return( -1 );
421 
422 	if( vips_check_coding_known( class->nickname, resample->in ) )
423 		return( -1 );
424 	if( vips_check_vector_length( class->nickname,
425 		affine->matrix->n, 4 ) )
426 		return( -1 );
427 	if( vips_object_argument_isset( object, "oarea" ) &&
428 		vips_check_vector_length( class->nickname,
429 			affine->oarea->n, 4 ) )
430 		return( -1 );
431 
432 	/* Can be set explicitly to NULL to mean default setting.
433 	 */
434 	if( !affine->interpolate )
435 		affine->interpolate = vips_interpolate_new( "bilinear" );
436 
437 	in = resample->in;
438 
439 	/* Set up transform.
440 	 */
441 
442 	window_size = vips_interpolate_get_window_size( affine->interpolate );
443 	window_offset =
444 		vips_interpolate_get_window_offset( affine->interpolate );
445 
446 	affine->trn.iarea.left = 0;
447 	affine->trn.iarea.top = 0;
448 	affine->trn.iarea.width = in->Xsize;
449 	affine->trn.iarea.height = in->Ysize;
450 	affine->trn.a = ((double *) affine->matrix->data)[0];
451 	affine->trn.b = ((double *) affine->matrix->data)[1];
452 	affine->trn.c = ((double *) affine->matrix->data)[2];
453 	affine->trn.d = ((double *) affine->matrix->data)[3];
454 	affine->trn.idx = 0;
455 	affine->trn.idy = 0;
456 	affine->trn.odx = 0;
457 	affine->trn.ody = 0;
458 
459 	if( vips__transform_calc_inverse( &affine->trn ) )
460 		return( -1 );
461 
462 	/* Set the default value for oarea.
463 	 */
464 	vips__transform_set_area( &affine->trn );
465 
466 	if( vips_object_argument_isset( object, "oarea" ) ) {
467 		affine->trn.oarea.left = ((int *) affine->oarea->data)[0];
468 		affine->trn.oarea.top = ((int *) affine->oarea->data)[1];
469 		affine->trn.oarea.width = ((int *) affine->oarea->data)[2];
470 		affine->trn.oarea.height = ((int *) affine->oarea->data)[3];
471 	}
472 
473 	if( vips_object_argument_isset( object, "odx" ) )
474 		affine->trn.odx = affine->odx;
475 	if( vips_object_argument_isset( object, "ody" ) )
476 		affine->trn.ody = affine->ody;
477 
478 	if( vips_object_argument_isset( object, "idx" ) )
479 		affine->trn.idx = affine->idx;
480 	if( vips_object_argument_isset( object, "idy" ) )
481 		affine->trn.idy = affine->idy;
482 
483 #ifdef DEBUG
484 	printf( "vips_affine_build: copy on identity transform disabled\n" );
485 #else /*!DEBUG*/
486 	if( vips__transform_isidentity( &affine->trn ) &&
487 		affine->trn.oarea.left == 0 &&
488 		affine->trn.oarea.top == 0 &&
489 		affine->trn.oarea.width == in->Xsize &&
490 		affine->trn.oarea.height == in->Ysize )
491 		return( vips_image_write( in, resample->out ) );
492 #endif /*!DEBUG*/
493 
494 	/* Check for coordinate overflow ... we want to be able to hold the
495 	 * output space inside INT_MAX / TRANSFORM_SCALE.
496 	 */
497 	edge = (int) (INT_MAX / VIPS_TRANSFORM_SCALE);
498 	if( affine->trn.oarea.left < -edge ||
499 		affine->trn.oarea.top < -edge ||
500 		VIPS_RECT_RIGHT( &affine->trn.oarea ) > edge ||
501 		VIPS_RECT_BOTTOM( &affine->trn.oarea ) > edge ) {
502 		vips_error( class->nickname,
503 			"%s", _( "output coordinates out of range" ) );
504 		return( -1 );
505 	}
506 
507 	if( vips_image_decode( in, &t[0] ) )
508 		return( -1 );
509 	in = t[0];
510 
511 	/* Add new pixels around the input so we can interpolate at the edges.
512 	 *
513 	 * We add the interpolate stencil, plus one extra pixel on all the
514 	 * edges. This means when we clip in generate (above) we can be sure
515 	 * we clip outside the real pixels and don't get jaggies on edges.
516 	 */
517 	if( vips_embed( in, &t[2],
518 		window_offset + 1, window_offset + 1,
519 		in->Xsize + window_size - 1 + 2,
520 		in->Ysize + window_size - 1 + 2,
521 		"extend", affine->extend,
522 		"background", affine->background,
523 		NULL ) )
524 		return( -1 );
525 	in = t[2];
526 
527 	/* We've added a one-pixel border to the input: displace the transform
528 	 * to compensate.
529 	 */
530 	affine->trn.idx -= 1;
531 	affine->trn.idy -= 1;
532 
533 	/* If there's an alpha and we've not premultiplied, we have to
534 	 * premultiply before resampling. See
535 	 * https://github.com/libvips/libvips/issues/291
536 	 */
537 	have_premultiplied = FALSE;
538 	if( vips_image_hasalpha( in ) &&
539 		!affine->premultiplied ) {
540 		if( vips_premultiply( in, &t[3], NULL ) )
541 			return( -1 );
542 		have_premultiplied = TRUE;
543 
544 		/* vips_premultiply() makes a float image. When we
545 		 * vips_unpremultiply() below, we need to cast back to the
546 		 * pre-premultiply format.
547 		 */
548 		unpremultiplied_format = in->BandFmt;
549 		in = t[3];
550 	}
551 
552 	/* Convert the background to the image's format.
553 	 */
554 	if( !(affine->ink = vips__vector_to_ink( class->nickname,
555 		in,
556 		VIPS_AREA( affine->background )->data, NULL,
557 		VIPS_AREA( affine->background )->n )) )
558 		return( -1 );
559 
560 	/* Normally SMALLTILE ... except if this is strictly a size
561 	 * up/down affine.
562 	 */
563 	if( affine->trn.b == 0.0 &&
564 		affine->trn.c == 0.0 )
565 		hint = VIPS_DEMAND_STYLE_FATSTRIP;
566 	else
567 		hint = VIPS_DEMAND_STYLE_SMALLTILE;
568 
569 	t[4] = vips_image_new();
570 	if( vips_image_pipelinev( t[4], hint, in, NULL ) )
571 		return( -1 );
572 
573 	t[4]->Xsize = affine->trn.oarea.width;
574 	t[4]->Ysize = affine->trn.oarea.height;
575 
576 #ifdef DEBUG
577 	printf( "vips_affine_build: transform: " );
578 	vips__transform_print( &affine->trn );
579 	printf( " window_offset = %d, window_size = %d\n",
580 		window_offset, window_size );
581 	printf( " input image width = %d, height = %d\n",
582 		in->Xsize, in->Ysize );
583 	printf( " output image width = %d, height = %d\n",
584 		t[4]->Xsize, t[4]->Ysize );
585 #endif /*DEBUG*/
586 
587 	/* Generate!
588 	 */
589 	if( vips_image_generate( t[4],
590 		vips_start_one, vips_affine_gen, vips_stop_one,
591 		in, affine ) )
592 		return( -1 );
593 
594 	/* Finally: can now set Xoffset/Yoffset.
595 	 */
596 	t[4]->Xoffset = affine->trn.odx - affine->trn.oarea.left;
597 	t[4]->Yoffset = affine->trn.ody - affine->trn.oarea.top;
598 
599 	in = t[4];
600 
601 	if( have_premultiplied ) {
602 		if( vips_unpremultiply( in, &t[5], NULL ) ||
603 			vips_cast( t[5], &t[6], unpremultiplied_format, NULL ) )
604 			return( -1 );
605 		in = t[6];
606 	}
607 
608 	if( vips_image_write( in, resample->out ) )
609 		return( -1 );
610 
611 	return( 0 );
612 }
613 
614 static void
vips_affine_class_init(VipsAffineClass * class)615 vips_affine_class_init( VipsAffineClass *class )
616 {
617 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
618 	VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
619 
620 	VIPS_DEBUG_MSG( "vips_affine_class_init\n" );
621 
622 	gobject_class->set_property = vips_object_set_property;
623 	gobject_class->get_property = vips_object_get_property;
624 
625 	vobject_class->nickname = "affine";
626 	vobject_class->description = _( "affine transform of an image" );
627 	vobject_class->build = vips_affine_build;
628 
629 	VIPS_ARG_BOXED( class, "matrix", 110,
630 		_( "Matrix" ),
631 		_( "Transformation matrix" ),
632 		VIPS_ARGUMENT_REQUIRED_INPUT,
633 		G_STRUCT_OFFSET( VipsAffine, matrix ),
634 		VIPS_TYPE_ARRAY_DOUBLE );
635 
636 	VIPS_ARG_INTERPOLATE( class, "interpolate", 2,
637 		_( "Interpolate" ),
638 		_( "Interpolate pixels with this" ),
639 		VIPS_ARGUMENT_OPTIONAL_INPUT,
640 		G_STRUCT_OFFSET( VipsAffine, interpolate ) );
641 
642 	VIPS_ARG_BOXED( class, "oarea", 111,
643 		_( "Output rect" ),
644 		_( "Area of output to generate" ),
645 		VIPS_ARGUMENT_OPTIONAL_INPUT,
646 		G_STRUCT_OFFSET( VipsAffine, oarea ),
647 		VIPS_TYPE_ARRAY_INT );
648 
649 	VIPS_ARG_DOUBLE( class, "odx", 112,
650 		_( "Output offset" ),
651 		_( "Horizontal output displacement" ),
652 		VIPS_ARGUMENT_OPTIONAL_INPUT,
653 		G_STRUCT_OFFSET( VipsAffine, odx ),
654 		-10000000, 10000000, 0 );
655 
656 	VIPS_ARG_DOUBLE( class, "ody", 113,
657 		_( "Output offset" ),
658 		_( "Vertical output displacement" ),
659 		VIPS_ARGUMENT_OPTIONAL_INPUT,
660 		G_STRUCT_OFFSET( VipsAffine, ody ),
661 		-10000000, 10000000, 0 );
662 
663 	VIPS_ARG_DOUBLE( class, "idx", 114,
664 		_( "Input offset" ),
665 		_( "Horizontal input displacement" ),
666 		VIPS_ARGUMENT_OPTIONAL_INPUT,
667 		G_STRUCT_OFFSET( VipsAffine, idx ),
668 		-10000000, 10000000, 0 );
669 
670 	VIPS_ARG_DOUBLE( class, "idy", 115,
671 		_( "Input offset" ),
672 		_( "Vertical input displacement" ),
673 		VIPS_ARGUMENT_OPTIONAL_INPUT,
674 		G_STRUCT_OFFSET( VipsAffine, idy ),
675 		-10000000, 10000000, 0 );
676 
677 	VIPS_ARG_ENUM( class, "extend", 117,
678 		_( "Extend" ),
679 		_( "How to generate the extra pixels" ),
680 		VIPS_ARGUMENT_OPTIONAL_INPUT,
681 		G_STRUCT_OFFSET( VipsAffine, extend ),
682 		VIPS_TYPE_EXTEND, VIPS_EXTEND_BACKGROUND );
683 
684 	VIPS_ARG_BOXED( class, "background", 116,
685 		_( "Background" ),
686 		_( "Background value" ),
687 		VIPS_ARGUMENT_OPTIONAL_INPUT,
688 		G_STRUCT_OFFSET( VipsAffine, background ),
689 		VIPS_TYPE_ARRAY_DOUBLE );
690 
691 	VIPS_ARG_BOOL( class, "premultiplied", 117,
692 		_( "Premultiplied" ),
693 		_( "Images have premultiplied alpha" ),
694 		VIPS_ARGUMENT_OPTIONAL_INPUT,
695 		G_STRUCT_OFFSET( VipsAffine, premultiplied ),
696 		FALSE );
697 
698 }
699 
700 static void
vips_affine_init(VipsAffine * affine)701 vips_affine_init( VipsAffine *affine )
702 {
703 	affine->extend = VIPS_EXTEND_BACKGROUND;
704 	affine->background = vips_array_double_newv( 1, 0.0 );
705 }
706 
707 /**
708  * vips_affine: (method)
709  * @in: input image
710  * @out: (out): output image
711  * @a: transformation matrix coefficient
712  * @b: transformation matrix coefficient
713  * @c: transformation matrix coefficient
714  * @d: transformation matrix coefficient
715  * @...: %NULL-terminated list of optional named arguments
716  *
717  * Optional arguments:
718  *
719  * * @interpolate: #VipsInterpolate, interpolate pixels with this
720  * * @oarea: #VipsArrayInt, output rectangle
721  * * @idx: %gdouble, input horizontal offset
722  * * @idy: %gdouble, input vertical offset
723  * * @odx: %gdouble, output horizontal offset
724  * * @ody: %gdouble, output vertical offset
725  * * @extend: #VipsExtend how to generate new pixels
726  * * @background: #VipsArrayDouble colour for new pixels
727  * * @premultiplied: %gboolean, images are already premultiplied
728  *
729  * This operator performs an affine transform on an image using @interpolate.
730  *
731  * The transform is:
732  *
733  * |[
734  *   X = @a * (x + @idx) + @b * (y + @idy) + @odx
735  *   Y = @c * (x + @idx) + @d * (y + @idy) + @doy
736  *
737  *   where:
738  *     x and y are the coordinates in input image.
739  *     X and Y are the coordinates in output image.
740  *     (0,0) is the upper left corner.
741  * ]|
742  *
743  * The section of the output space defined by @oarea is written to
744  * @out. @oarea is a four-element int array of left, top, width, height.
745  * By default @oarea is just large enough to cover the whole of the
746  * transformed input image.
747  *
748  * By default, new pixels are filled with @background. This defaults to
749  * zero (black). You can set other extend types with @extend. #VIPS_EXTEND_COPY
750  * is better for image upsizing.
751  *
752  * @interpolate defaults to bilinear.
753  *
754  * @idx, @idy, @odx, @ody default to zero.
755  *
756  * Image are normally treated as unpremultiplied, so this operation can be used
757  * directly on PNG images. If your images have been through vips_premultiply(),
758  * set @premultiplied.
759  *
760  * This operation does not change xres or yres. The image resolution needs to
761  * be updated by the application.
762  *
763  * See also: vips_shrink(), vips_resize(), #VipsInterpolate.
764  *
765  * Returns: 0 on success, -1 on error
766  */
767 int
vips_affine(VipsImage * in,VipsImage ** out,double a,double b,double c,double d,...)768 vips_affine( VipsImage *in, VipsImage **out,
769 	double a, double b, double c, double d, ... )
770 {
771 	va_list ap;
772 	VipsArea *matrix;
773 	int result;
774 
775 	matrix = VIPS_AREA( vips_array_double_newv( 4, a, b, c, d ) );
776 
777 	va_start( ap, d );
778 	result = vips_call_split( "affine", ap, in, out, matrix );
779 	va_end( ap );
780 
781 	vips_area_unref( matrix );
782 
783 	return( result );
784 }
785