1 /* vipsinterpolate ... abstract base class for various interpolators
2  *
3  * J. Cupitt, 15/10/08
4  *
5  * 12/8/10
6  * 	- revise window_size / window_offset stuff again: window_offset now
7  * 	  defaults to (window_size / 2 - 1), so for a 4x4 stencil (eg.
8  * 	  bicubic) we have an offset of 1
9  * 	- tiny speedups
10  * 7/1/11
11  * 	- don't use tables for bilinear on float data for a small speedup
12  * 	  (thanks Nicolas Robidoux)
13  * 12/1/11
14  * 	- faster, more accuarate uchar bilinear (thanks Nicolas)
15  * 2/2/11
16  * 	- gtk-doc
17  * 16/12/15
18  * 	- faster bilinear
19  * 27/2/19 s-sajid-ali
20  * 	- more accurate bilinear
21  */
22 
23 /*
24 
25     This file is part of VIPS.
26 
27     VIPS is free software; you can redistribute it and/or modify
28     it under the terms of the GNU Lesser General Public License as published by
29     the Free Software Foundation; either version 2 of the License, or
30     (at your option) any later version.
31 
32     This program is distributed in the hope that it will be useful,
33     but WITHOUT ANY WARRANTY; without even the implied warranty of
34     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
35     GNU Lesser General Public License for more details.
36 
37     You should have received a copy of the GNU Lesser General Public License
38     along with this program; if not, write to the Free Software
39     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
40     02110-1301  USA
41 
42  */
43 
44 /*
45 
46     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
47 
48  */
49 
50 /*
51 #define DEBUG
52  */
53 
54 #ifdef HAVE_CONFIG_H
55 #include <config.h>
56 #endif /*HAVE_CONFIG_H*/
57 #include <vips/intl.h>
58 
59 #include <stdio.h>
60 #include <stdlib.h>
61 
62 #include <vips/vips.h>
63 #include <vips/internal.h>
64 
65 /**
66  * SECTION: interpolator
67  * @short_description: various interpolators: nearest, bilinear, and
68  * some non-linear
69  * @stability: Stable
70  * @include: vips/vips.h
71  *
72  * A number of image interpolators.
73  */
74 
75 G_DEFINE_ABSTRACT_TYPE( VipsInterpolate, vips_interpolate, VIPS_TYPE_OBJECT );
76 
77 /**
78  * VipsInterpolateMethod:
79  * @interpolate: the interpolator
80  * @out: write the interpolated pixel here
81  * @in: read source pixels from here
82  * @x: interpolate value at this position
83  * @y: interpolate value at this position
84  *
85  * An interpolation function. It should read source pixels from @in with
86  * VIPS_REGION_ADDR(), it can look left and up from (x, y) by @window_offset
87  * pixels and it can access pixels in a window of size @window_size.
88  *
89  * The interpolated value should be written to the pixel pointed to by @out.
90  *
91  * See also: #VipsInterpolateClass.
92  */
93 
94 /**
95  * VipsInterpolateClass:
96  * @interpolate: the interpolation method
97  * @get_window_size: return the size of the window needed by this method
98  * @window_size: or just set this for a constant window size
99  * @get_window_offset: return the window offset for this method
100  * @window_offset: or just set this for a constant window offset
101  *
102  * The abstract base class for the various VIPS interpolation functions.
103  * Use "vips --list classes" to see all the interpolators available.
104  *
105  * An interpolator consists of a function to perform the interpolation, plus
106  * some extra data fields which tell vips how to call the function and what
107  * data it needs.
108  *
109  * @window_size is the size of the window that the interpolator needs. For
110  * example, a bicubic interpolator needs to see a window of 4x4 pixels to be
111  * able to interpolate a value.
112  *
113  * You can either have a function in @get_window_size which returns the window
114  * that a specific interpolator needs, or you can leave @get_window_size %NULL
115  * and set a constant value in @window_size.
116  *
117  * @window_offset is how much to offset the window up and left of (x, y). For
118  * example, a bicubic interpolator will want a @window_offset of 1.
119  *
120  * You can either have a function in @get_window_offset which returns the
121  * offset that a specific interpolator needs, or you can leave
122  * @get_window_offset %NULL and set a constant value in @window_offset.
123  *
124  * You also need to set @nickname and @description in #VipsObject.
125  *
126  * See also: #VipsInterpolateMethod, #VipsObject,
127  * vips_interpolate_bilinear_static().
128  */
129 
130 #ifdef DEBUG
131 static void
vips_interpolate_finalize(GObject * gobject)132 vips_interpolate_finalize( GObject *gobject )
133 {
134 	printf( "vips_interpolate_finalize: " );
135 	vips_object_print_name( VIPS_OBJECT( gobject ) );
136 
137 	G_OBJECT_CLASS( vips_interpolate_parent_class )->finalize( gobject );
138 }
139 #endif /*DEBUG*/
140 
141 static int
vips_interpolate_real_get_window_size(VipsInterpolate * interpolate)142 vips_interpolate_real_get_window_size( VipsInterpolate *interpolate )
143 {
144 	VipsInterpolateClass *class = VIPS_INTERPOLATE_GET_CLASS( interpolate );
145 
146 	g_assert( class->window_size != -1 );
147 
148 	return( class->window_size );
149 }
150 
151 static int
vips_interpolate_real_get_window_offset(VipsInterpolate * interpolate)152 vips_interpolate_real_get_window_offset( VipsInterpolate *interpolate )
153 {
154 	VipsInterpolateClass *class = VIPS_INTERPOLATE_GET_CLASS( interpolate );
155 
156  	/* Default to half window size - 1. For example, bicubic is a 4x4
157 	 * stencil and needs an offset of 1.
158  	 */
159 	if( class->window_offset != -1 )
160 		return( class->window_offset );
161 	else {
162 		int window_size =
163 			vips_interpolate_get_window_size( interpolate );
164 
165 		/* Don't go -ve, of course, for window_size 1.
166 		 */
167 		return( VIPS_MAX( 0, window_size / 2 - 1 ) );
168 	}
169 }
170 
171 static void
vips_interpolate_class_init(VipsInterpolateClass * class)172 vips_interpolate_class_init( VipsInterpolateClass *class )
173 {
174 	VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
175 
176 #ifdef DEBUG
177 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
178 #endif /*DEBUG*/
179 
180 #ifdef DEBUG
181 	gobject_class->finalize = vips_interpolate_finalize;
182 #endif /*DEBUG*/
183 
184 	vobject_class->nickname = "interpolate";
185 	vobject_class->description = _( "VIPS interpolators" );
186 
187 	class->interpolate = NULL;
188 	class->get_window_size = vips_interpolate_real_get_window_size;
189 	class->get_window_offset = vips_interpolate_real_get_window_offset;
190 	class->window_size = -1;
191 	class->window_offset = -1;
192 }
193 
194 static void
vips_interpolate_init(VipsInterpolate * interpolate)195 vips_interpolate_init( VipsInterpolate *interpolate )
196 {
197 #ifdef DEBUG
198 	printf( "vips_interpolate_init: " );
199 	vips_object_print_name( VIPS_OBJECT( interpolate ) );
200 #endif /*DEBUG*/
201 }
202 
203 /**
204  * vips_interpolate: (skip)
205  * @interpolate: interpolator to use
206  * @out: write result here
207  * @in: read source data from here
208  * @x: interpolate value at this position
209  * @y: interpolate value at this position
210  *
211  * Look up the @interpolate method in the class and call it. Use
212  * vips_interpolate_get_method() to get a direct pointer to the function and
213  * avoid the lookup overhead.
214  *
215  * You need to set @in and @out up correctly.
216  */
217 void
vips_interpolate(VipsInterpolate * interpolate,void * out,VipsRegion * in,double x,double y)218 vips_interpolate( VipsInterpolate *interpolate,
219 	void *out, VipsRegion *in, double x, double y )
220 {
221 	VipsInterpolateClass *class = VIPS_INTERPOLATE_GET_CLASS( interpolate );
222 
223 	g_assert( class->interpolate );
224 
225 	class->interpolate( interpolate, out, in, x, y );
226 }
227 
228 /**
229  * vips_interpolate_get_method: (skip)
230  * @interpolate: interpolator to use
231  *
232  * Look up the @interpolate method in the class and return it. Use this
233  * instead of vips_interpolate() to cache method dispatch.
234  *
235  * Returns: a pointer to the interpolation function
236  */
237 VipsInterpolateMethod
vips_interpolate_get_method(VipsInterpolate * interpolate)238 vips_interpolate_get_method( VipsInterpolate *interpolate )
239 {
240 	VipsInterpolateClass *class = VIPS_INTERPOLATE_GET_CLASS( interpolate );
241 
242 	g_assert( class->interpolate );
243 
244 	return( class->interpolate );
245 }
246 
247 /**
248  * vips_interpolate_get_window_size:
249  * @interpolate: interpolator to use
250  *
251  * Look up an interpolators desired window size.
252  *
253  * Returns: the interpolators required window size
254  */
255 int
vips_interpolate_get_window_size(VipsInterpolate * interpolate)256 vips_interpolate_get_window_size( VipsInterpolate *interpolate )
257 {
258 	VipsInterpolateClass *class = VIPS_INTERPOLATE_GET_CLASS( interpolate );
259 
260 	g_assert( class->get_window_size );
261 
262 	return( class->get_window_size( interpolate ) );
263 }
264 
265 /**
266  * vips_interpolate_get_window_offset:
267  * @interpolate: interpolator to use
268  *
269  * Look up an interpolators desired window offset.
270  *
271  * Returns: the interpolators required window offset
272  */
273 int
vips_interpolate_get_window_offset(VipsInterpolate * interpolate)274 vips_interpolate_get_window_offset( VipsInterpolate *interpolate )
275 {
276 	VipsInterpolateClass *class = VIPS_INTERPOLATE_GET_CLASS( interpolate );
277 
278 	g_assert( class->get_window_offset );
279 
280 	return( class->get_window_offset( interpolate ) );
281 }
282 
283 /**
284  * VIPS_TRANSFORM_SHIFT:
285  *
286  * Many of the vips interpolators use fixed-point arithmetic for coordinate
287  * calculation. This is how many bits of precision they use.
288  */
289 
290 /**
291  * VIPS_TRANSFORM_SCALE:
292  *
293  * #VIPS_TRANSFORM_SHIFT as a multiplicative constant.
294  */
295 
296 /**
297  * VIPS_INTERPOLATE_SHIFT:
298  *
299  * Many of the vips interpolators use fixed-point arithmetic for value
300  * calcualtion. This is how many bits of precision they use.
301  */
302 
303 /**
304  * VIPS_INTERPOLATE_SCALE:
305  *
306  * #VIPS_INTERPOLATE_SHIFT as a multiplicative constant.
307  */
308 
309 /* VipsInterpolateNearest class
310  */
311 
312 #define VIPS_TYPE_INTERPOLATE_NEAREST (vips_interpolate_nearest_get_type())
313 #define VIPS_INTERPOLATE_NEAREST( obj ) \
314 	(G_TYPE_CHECK_INSTANCE_CAST( (obj), \
315 	VIPS_TYPE_INTERPOLATE_NEAREST, VipsInterpolateNearest ))
316 #define VIPS_INTERPOLATE_NEAREST_CLASS( klass ) \
317 	(G_TYPE_CHECK_CLASS_CAST( (klass), \
318 	VIPS_TYPE_INTERPOLATE_NEAREST, VipsInterpolateNearestClass))
319 #define VIPS_IS_INTERPOLATE_NEAREST( obj ) \
320 	(G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_INTERPOLATE_NEAREST ))
321 #define VIPS_IS_INTERPOLATE_NEAREST_CLASS( klass ) \
322 	(G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_INTERPOLATE_NEAREST ))
323 #define VIPS_INTERPOLATE_NEAREST_GET_CLASS( obj ) \
324 	(G_TYPE_INSTANCE_GET_CLASS( (obj), \
325 	VIPS_TYPE_INTERPOLATE_NEAREST, VipsInterpolateNearestClass ))
326 
327 /* No new members.
328  */
329 typedef VipsInterpolate VipsInterpolateNearest;
330 typedef VipsInterpolateClass VipsInterpolateNearestClass;
331 
332 G_DEFINE_TYPE( VipsInterpolateNearest, vips_interpolate_nearest,
333 	VIPS_TYPE_INTERPOLATE );
334 
335 static void
vips_interpolate_nearest_interpolate(VipsInterpolate * interpolate,void * out,VipsRegion * in,double x,double y)336 vips_interpolate_nearest_interpolate( VipsInterpolate *interpolate,
337 	void *out, VipsRegion *in, double x, double y )
338 {
339 	const int ps = VIPS_IMAGE_SIZEOF_PEL( in->im );
340 
341 	const int xi = (int) x;
342 	const int yi = (int) y;
343 
344 	const VipsPel * restrict p = VIPS_REGION_ADDR( in, xi, yi );
345 	VipsPel * restrict q = (VipsPel *) out;
346 
347 	int z;
348 
349 	for( z = 0; z < ps; z++ )
350 		q[z] = p[z];
351 }
352 
353 static void
vips_interpolate_nearest_class_init(VipsInterpolateNearestClass * class)354 vips_interpolate_nearest_class_init( VipsInterpolateNearestClass *class )
355 {
356 	VipsObjectClass *object_class = VIPS_OBJECT_CLASS( class );
357 	VipsInterpolateClass *interpolate_class =
358 		VIPS_INTERPOLATE_CLASS( class );
359 
360 	object_class->nickname = "nearest";
361 	object_class->description = _( "nearest-neighbour interpolation" );
362 
363 	interpolate_class->interpolate = vips_interpolate_nearest_interpolate;
364 	interpolate_class->window_size = 1;
365 }
366 
367 static void
vips_interpolate_nearest_init(VipsInterpolateNearest * nearest)368 vips_interpolate_nearest_init( VipsInterpolateNearest *nearest )
369 {
370 #ifdef DEBUG
371 	printf( "vips_interpolate_nearest_init: " );
372 	vips_object_print_name( VIPS_OBJECT( nearest ) );
373 #endif /*DEBUG*/
374 }
375 
376 VipsInterpolate *
vips_interpolate_nearest_new(void)377 vips_interpolate_nearest_new( void )
378 {
379 	return( VIPS_INTERPOLATE( vips_object_new(
380 		VIPS_TYPE_INTERPOLATE_NEAREST, NULL, NULL, NULL ) ) );
381 }
382 
383 /**
384  * vips_interpolate_nearest_static:
385  *
386  * A convenience function that returns a nearest-neighbour interpolator you
387  * don't need to free.
388  *
389  * Returns: (transfer none): a nearest-neighbour interpolator
390  */
391 VipsInterpolate *
vips_interpolate_nearest_static(void)392 vips_interpolate_nearest_static( void )
393 {
394 	static VipsInterpolate *interpolate = NULL;
395 
396 	if( !interpolate ) {
397 		interpolate = vips_interpolate_nearest_new();
398 		vips_object_set_static( VIPS_OBJECT( interpolate ), TRUE );
399 	}
400 
401 	return( interpolate );
402 }
403 
404 /* VipsInterpolateBilinear class
405  */
406 
407 #define VIPS_TYPE_INTERPOLATE_BILINEAR (vips_interpolate_bilinear_get_type())
408 #define VIPS_INTERPOLATE_BILINEAR( obj ) \
409 	(G_TYPE_CHECK_INSTANCE_CAST( (obj), \
410 	VIPS_TYPE_INTERPOLATE_BILINEAR, VipsInterpolateBilinear ))
411 #define VIPS_INTERPOLATE_BILINEAR_CLASS( klass ) \
412 	(G_TYPE_CHECK_CLASS_CAST( (klass), \
413 	VIPS_TYPE_INTERPOLATE_BILINEAR, VipsInterpolateBilinearClass))
414 #define VIPS_IS_INTERPOLATE_BILINEAR( obj ) \
415 	(G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_INTERPOLATE_BILINEAR ))
416 #define VIPS_IS_INTERPOLATE_BILINEAR_CLASS( klass ) \
417 	(G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_INTERPOLATE_BILINEAR ))
418 #define VIPS_INTERPOLATE_BILINEAR_GET_CLASS( obj ) \
419 	(G_TYPE_INSTANCE_GET_CLASS( (obj), \
420 	VIPS_TYPE_INTERPOLATE_BILINEAR, VipsInterpolateBilinearClass ))
421 
422 typedef VipsInterpolate VipsInterpolateBilinear;
423 typedef VipsInterpolateClass VipsInterpolateBilinearClass;
424 
425 G_DEFINE_TYPE( VipsInterpolateBilinear, vips_interpolate_bilinear,
426 	VIPS_TYPE_INTERPOLATE );
427 
428 /* in this class, name vars in the 2x2 grid as eg.
429  * p1  p2
430  * p3  p4
431  */
432 
433 #define BILINEAR_INT_INNER { \
434 	tq[z] = (c1 * tp1[z] + c2 * tp2[z] + \
435 		 c3 * tp3[z] + c4 * tp4[z] + \
436 		 (1 << VIPS_INTERPOLATE_SHIFT) / 2) >> VIPS_INTERPOLATE_SHIFT; \
437 	z += 1; \
438 }
439 
440 /* Fixed-point arithmetic, no tables.
441  */
442 #define BILINEAR_INT( TYPE ) { \
443 	TYPE * restrict tq = (TYPE *) out; \
444 	\
445 	int X = (x - ix) * VIPS_INTERPOLATE_SCALE; \
446 	int Y = (y - iy) * VIPS_INTERPOLATE_SCALE; \
447 	\
448 	int Yd = VIPS_INTERPOLATE_SCALE - Y; \
449         \
450 	int c4 = (Y * X) >> VIPS_INTERPOLATE_SHIFT; \
451 	int c2 = (Yd * X) >> VIPS_INTERPOLATE_SHIFT; \
452 	int c3 = Y - c4; \
453 	int c1 = Yd - c2; \
454 	\
455 	const TYPE * restrict tp1 = (TYPE *) p1; \
456 	const TYPE * restrict tp2 = (TYPE *) p2; \
457 	const TYPE * restrict tp3 = (TYPE *) p3; \
458 	const TYPE * restrict tp4 = (TYPE *) p4; \
459 	\
460 	z = 0; \
461 	VIPS_UNROLL( b, BILINEAR_INT_INNER ); \
462 }
463 
464 #define BILINEAR_FLOAT_INNER { \
465 	tq[z] = c1 * tp1[z] + c2 * tp2[z] + \
466 		c3 * tp3[z] + c4 * tp4[z]; \
467 	z += 1; \
468 }
469 
470 /* Interpolate a pel ... int16, int32 and float types, no tables, float
471  * arithmetic. Use double not float for coefficient calculation or we can
472  * get small over/undershoots.
473  */
474 #define BILINEAR_FLOAT( TYPE ) { \
475 	TYPE * restrict tq = (TYPE *) out; \
476 	\
477 	double X = x - ix; \
478 	double Y = y - iy; \
479         \
480 	double Yd = 1.0f - Y; \
481         \
482 	double c4 = Y * X; \
483 	double c2 = Yd * X; \
484 	double c3 = Y - c4; \
485 	double c1 = Yd - c2; \
486  	\
487 	const TYPE * restrict tp1 = (TYPE *) p1; \
488 	const TYPE * restrict tp2 = (TYPE *) p2; \
489 	const TYPE * restrict tp3 = (TYPE *) p3; \
490 	const TYPE * restrict tp4 = (TYPE *) p4; \
491 	\
492 	z = 0; \
493 	VIPS_UNROLL( b, BILINEAR_FLOAT_INNER ); \
494 }
495 
496 /* The fixed-point path is fine for uchar pixels, but it'll be inaccurate for
497  * shorts and larger.
498  */
499 #define SWITCH_INTERPOLATE( FMT, INT, FLOAT ) { \
500 	switch( (FMT) ) { \
501 	case VIPS_FORMAT_UCHAR:	INT( unsigned char ); break; \
502 	case VIPS_FORMAT_CHAR: 	INT( char ); break; \
503 	case VIPS_FORMAT_USHORT:INT( unsigned short ); break; \
504 	case VIPS_FORMAT_SHORT: INT( short ); break; \
505 	case VIPS_FORMAT_UINT: 	FLOAT( unsigned int ); break; \
506 	case VIPS_FORMAT_INT: 	FLOAT( int );  break; \
507 	case VIPS_FORMAT_FLOAT: FLOAT( float ); break; \
508 	case VIPS_FORMAT_DOUBLE:FLOAT( double ); break; \
509 	case VIPS_FORMAT_COMPLEX: FLOAT( float ); break; \
510 	case VIPS_FORMAT_DPCOMPLEX:FLOAT( double ); break; \
511 	default: \
512 		g_assert( FALSE ); \
513 	} \
514 }
515 
516 static void
vips_interpolate_bilinear_interpolate(VipsInterpolate * interpolate,void * out,VipsRegion * in,double x,double y)517 vips_interpolate_bilinear_interpolate( VipsInterpolate *interpolate,
518 	void *out, VipsRegion *in, double x, double y )
519 {
520 	/* Pel size and line size.
521 	 */
522 	const int ps = VIPS_IMAGE_SIZEOF_PEL( in->im );
523 	const int ls = VIPS_REGION_LSKIP( in );
524 	const int b = in->im->Bands *
525 		(vips_band_format_iscomplex( in->im->BandFmt ) ?  2 : 1);
526 
527 	const int ix = (int) x;
528 	const int iy = (int) y;
529 
530 	const VipsPel * restrict p1 = VIPS_REGION_ADDR( in, ix, iy );
531 	const VipsPel * restrict p2 = p1 + ps;
532 	const VipsPel * restrict p3 = p1 + ls;
533 	const VipsPel * restrict p4 = p3 + ps;
534 
535 	int z;
536 
537 	g_assert( (int) x >= in->valid.left );
538 	g_assert( (int) y >= in->valid.top );
539 	g_assert( (int) x + 1 < VIPS_RECT_RIGHT( &in->valid ) );
540 	g_assert( (int) y + 1 < VIPS_RECT_BOTTOM( &in->valid ) );
541 
542 	SWITCH_INTERPOLATE( in->im->BandFmt, BILINEAR_INT, BILINEAR_FLOAT );
543 }
544 
545 static void
vips_interpolate_bilinear_class_init(VipsInterpolateBilinearClass * class)546 vips_interpolate_bilinear_class_init( VipsInterpolateBilinearClass *class )
547 {
548 	VipsObjectClass *object_class = VIPS_OBJECT_CLASS( class );
549 	VipsInterpolateClass *interpolate_class =
550 		(VipsInterpolateClass *) class;
551 
552 	object_class->nickname = "bilinear";
553 	object_class->description = _( "bilinear interpolation" );
554 
555 	interpolate_class->interpolate = vips_interpolate_bilinear_interpolate;
556 	interpolate_class->window_size = 2;
557 }
558 
559 static void
vips_interpolate_bilinear_init(VipsInterpolateBilinear * bilinear)560 vips_interpolate_bilinear_init( VipsInterpolateBilinear *bilinear )
561 {
562 #ifdef DEBUG
563 	printf( "vips_interpolate_bilinear_init: " );
564 	vips_object_print_name( VIPS_OBJECT( bilinear ) );
565 #endif /*DEBUG*/
566 
567 }
568 
569 VipsInterpolate *
vips_interpolate_bilinear_new(void)570 vips_interpolate_bilinear_new( void )
571 {
572 	return( VIPS_INTERPOLATE( vips_object_new(
573 		VIPS_TYPE_INTERPOLATE_BILINEAR, NULL, NULL, NULL ) ) );
574 }
575 
576 /**
577  * vips_interpolate_bilinear_static:
578  *
579  * A convenience function that returns a bilinear interpolator you
580  * don't need to free.
581  *
582  * Returns: (transfer none): a bilinear interpolator
583  */
584 VipsInterpolate *
vips_interpolate_bilinear_static(void)585 vips_interpolate_bilinear_static( void )
586 {
587 	static VipsInterpolate *interpolate = NULL;
588 
589 	if( !interpolate ) {
590 		interpolate = vips_interpolate_bilinear_new();
591 		vips_object_set_static( VIPS_OBJECT( interpolate ), TRUE );
592 	}
593 
594 	return( interpolate );
595 }
596 
597 /* Called on startup: register the base vips interpolators.
598  */
599 void
vips__interpolate_init(void)600 vips__interpolate_init( void )
601 {
602 	extern GType vips_interpolate_bicubic_get_type( void );
603 	extern GType vips_interpolate_lbb_get_type( void );
604 	extern GType vips_interpolate_nohalo_get_type( void );
605 	extern GType vips_interpolate_vsqbs_get_type( void );
606 
607 	vips_interpolate_nearest_get_type();
608 	vips_interpolate_bilinear_get_type();
609 
610 	vips_interpolate_bicubic_get_type();
611 	vips_interpolate_lbb_get_type();
612 	vips_interpolate_nohalo_get_type();
613 	vips_interpolate_vsqbs_get_type();
614 }
615 
616 /**
617  * vips_interpolate_new: (constructor)
618  * @nickname: nickname for interpolator
619  *
620  * Look up an interpolator from a nickname and make one. You need to free the
621  * result with g_object_unref() when you're done with it.
622  *
623  * See also: vips_type_find().
624  *
625  * Returns: an interpolator, or %NULL on error.
626  */
627 VipsInterpolate *
vips_interpolate_new(const char * nickname)628 vips_interpolate_new( const char *nickname )
629 {
630 	GType type;
631 
632 	if( !(type = vips_type_find( "VipsInterpolate", nickname )) ) {
633 		vips_error( "VipsInterpolate",
634 			_( "class \"%s\" not found" ), nickname );
635 		return( NULL );
636 	}
637 
638 	return( VIPS_INTERPOLATE( vips_object_new( type, NULL, NULL, NULL ) ) );
639 }
640