static void* interp_register(VipsInterpolateClass *itrp, void *hash) { VipsInterpolate *inst; VipsObjectClass *klass = (VipsObjectClass*) itrp;; VALUE obj, hVIPSInterpolators = (VALUE)hash; inst = vips_interpolate_new(klass->nickname); obj = Data_Wrap_Struct(cVIPSInterpolator, 0, 0, inst); rb_hash_aset(hVIPSInterpolators, ID2SYM(rb_intern(klass->nickname)), obj); return NULL; }
int main( int argc, char **argv ) { VipsImage *global; VipsImage **t; if( VIPS_INIT( argv[0] ) ) return( -1 ); global = vips_image_new(); t = (VipsImage **) vips_object_local_array( VIPS_OBJECT( global ), 5 ); VipsInterpolate *interp = vips_interpolate_new( "bilinear" ); if( !(t[0] = vips_image_new_from_file( argv[1], "access", VIPS_ACCESS_SEQUENTIAL, NULL )) ) vips_error_exit( NULL ); t[1] = vips_image_new_matrixv( 3, 3, -1.0, -1.0, -1.0, -1.0, 16.0, -1.0, -1.0, -1.0, -1.0 ); vips_image_set_double( t[1], "scale", 8 ); if( vips_extract_area( t[0], &t[2], 100, 100, t[0]->Xsize - 200, t[0]->Ysize - 200, NULL ) || vips_similarity( t[2], &t[3], "scale", 0.9, "interpolate", interp, NULL ) || vips_conv( t[3], &t[4], t[1], NULL ) || vips_image_write_to_file( t[4], argv[2], NULL ) ) vips_error_exit( NULL ); g_object_unref( global ); g_object_unref( interp ); return( 0 ); }
static int vips_mosaic1_build( VipsObject *object ) { VipsMosaic1 *mosaic1 = (VipsMosaic1 *) object; joinfn jfn; g_object_set( mosaic1, "out", vips_image_new(), NULL ); if( VIPS_OBJECT_CLASS( vips_mosaic1_parent_class )->build( object ) ) return( -1 ); if( !mosaic1->interpolate ) mosaic1->interpolate = vips_interpolate_new( "bilinear" ); jfn = mosaic1->direction == VIPS_DIRECTION_HORIZONTAL ? im__lrmerge1 : im__tbmerge1; if( mosaic1->search ) { if( rotjoin_search( mosaic1->ref, mosaic1->sec, mosaic1->out, jfn, mosaic1->bandno, mosaic1->xr1, mosaic1->yr1, mosaic1->xs1, mosaic1->ys1, mosaic1->xr2, mosaic1->yr2, mosaic1->xs2, mosaic1->ys2, mosaic1->hwindow, mosaic1->harea, 0, mosaic1->mblend ) ) return( -1 ); } else { if( rotjoin( mosaic1->ref, mosaic1->sec, mosaic1->out, jfn, mosaic1->xr1, mosaic1->yr1, mosaic1->xs1, mosaic1->ys1, mosaic1->xr2, mosaic1->yr2, mosaic1->xs2, mosaic1->ys2, mosaic1->mblend ) ) return( -1 ); } return( 0 ); }
static int vips_resize_build( VipsObject *object ) { VipsResample *resample = VIPS_RESAMPLE( object ); VipsResize *resize = (VipsResize *) object; VipsImage **t = (VipsImage **) vips_object_local_array( object, 7 ); VipsImage *in; int window_size; int int_shrink; int int_shrink_width; double residual; double sigma; if( VIPS_OBJECT_CLASS( vips_resize_parent_class )->build( object ) ) return( -1 ); if( !vips_object_argument_isset( object, "interpolate" ) ) { VipsInterpolate *interpolate; char *nick; if( vips_type_find( "VipsInterpolate", "bicubic" ) ) nick = "bicubic"; else nick = "bilinear"; interpolate = vips_interpolate_new( nick ); g_object_set( object, "interpolate", interpolate, NULL ); VIPS_UNREF( interpolate ); } in = resample->in; window_size = resize->interpolate ? vips_interpolate_get_window_size( resize->interpolate ) : 2; /* If the factor is > 1.0, we need to zoom rather than shrink. * Just set the int part to 1 in this case. */ int_shrink = resize->scale > 1.0 ? 1 : floor( 1.0 / resize->scale ); /* We want to shrink by less for interpolators with larger windows. */ int_shrink = VIPS_MAX( 1, int_shrink / VIPS_MAX( 1, window_size / 2 ) ); /* Size after int shrink. */ int_shrink_width = in->Xsize / int_shrink; /* Therefore residual scale factor is. */ residual = (in->Xsize * resize->scale) / int_shrink_width; /* A copy for enlarge resize. */ if( vips_shrink( in, &t[0], int_shrink, int_shrink, NULL ) ) return( -1 ); in = t[0]; /* We want to make sure we read the image sequentially. * However, the convolution we may be doing later will force us * into SMALLTILE or maybe FATSTRIP mode and that will break * sequentiality. * * So ... read into a cache where tiles are scanlines, and make sure * we keep enough scanlines to be able to serve a line of tiles. * * We use a threaded tilecache to avoid a deadlock: suppose thread1, * evaluating the top block of the output, is delayed, and thread2, * evaluating the second block, gets here first (this can happen on * a heavily-loaded system). * * With an unthreaded tilecache (as we had before), thread2 will get * the cache lock and start evaling the second block of the shrink. * When it reaches the png reader it will stall until the first block * has been used ... but it never will, since thread1 will block on * this cache lock. */ if( int_shrink > 1 ) { int tile_width; int tile_height; int nlines; vips_get_tile_size( in, &tile_width, &tile_height, &nlines ); if( vips_tilecache( in, &t[6], "tile_width", in->Xsize, "tile_height", 10, "max_tiles", 1 + (nlines * 2) / 10, "access", VIPS_ACCESS_SEQUENTIAL, "threaded", TRUE, NULL ) ) return( -1 ); in = t[6]; } /* If the final affine will be doing a large downsample, we can get * nasty aliasing on hard edges. Blur before affine to smooth this out. * * Don't blur for very small shrinks, blur with radius 1 for x1.5 * shrinks, blur radius 2 for x2.5 shrinks and above, etc. */ sigma = ((1.0 / residual) - 0.5) / 1.5; if( residual < 1.0 && sigma > 0.1 ) { if( vips_gaussblur( in, &t[2], sigma, NULL ) ) return( -1 ); in = t[2]; } if( vips_affine( in, &t[3], residual, 0, 0, residual, "interpolate", resize->interpolate, "idx", resize->idx, "idy", resize->idy, NULL ) ) return( -1 ); in = t[3]; /* If we are upsampling, don't sharpen. */ if( int_shrink > 1 ) { t[5] = vips_image_new_matrixv( 3, 3, -1.0, -1.0, -1.0, -1.0, 32.0, -1.0, -1.0, -1.0, -1.0 ); vips_image_set_double( t[5], "scale", 24 ); if( vips_conv( in, &t[4], t[5], NULL ) ) return( -1 ); in = t[4]; } if( vips_image_write( in, resample->out ) ) return( -1 ); return( 0 ); }