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