static int vips_colour_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop ) { VipsRegion **ir = (VipsRegion **) seq; VipsColour *colour = VIPS_COLOUR( b ); VipsColourClass *class = VIPS_COLOUR_GET_CLASS( colour ); VipsRect *r = &or->valid; int i, y; VipsPel *p[MAX_INPUT_IMAGES], *q; if( vips_reorder_prepare_many( or->im, ir, r ) ) return( -1 ); VIPS_GATE_START( "vips_colour_gen: work" ); for( y = 0; y < r->height; y++ ) { for( i = 0; ir[i]; i++ ) p[i] = VIPS_REGION_ADDR( ir[i], r->left, r->top + y ); p[i] = NULL; q = VIPS_REGION_ADDR( or, r->left, r->top + y ); class->process_line( colour, q, p, r->width ); } VIPS_GATE_STOP( "vips_colour_gen: work" ); VIPS_COUNT_PIXELS( or, VIPS_OBJECT_GET_CLASS( colour )->nickname ); return( 0 ); }
static int thumbnail3( IMAGE *in, IMAGE *out ) { int shrink; double residual; VipsInterpolate *interp; int result; shrink = calculate_shrink( in->Xsize, in->Ysize, &residual ); /* For images smaller than the thumbnail, we upscale with nearest * neighbor. Otherwise we makes thumbnails that look fuzzy and awful. */ if( !(interp = VIPS_INTERPOLATE( vips_object_new_from_string( g_type_class_ref( VIPS_TYPE_INTERPOLATE ), residual > 1.0 ? "nearest" : interpolator ) )) ) return( -1 ); if( verbose ) { printf( "integer shrink by %d\n", shrink ); printf( "residual scale by %g\n", residual ); printf( "%s interpolation\n", VIPS_OBJECT_GET_CLASS( interp )->nickname ); } result = shrink_factor( in, out, shrink, residual, interp ); g_object_unref( interp ); return( result ); }
static int vips_bandary_build( VipsObject *object ) { VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS( object ); VipsBandaryClass *class = VIPS_BANDARY_GET_CLASS( object ); VipsConversion *conversion = VIPS_CONVERSION( object ); VipsBandary *bandary = VIPS_BANDARY( object ); int i; VipsImage **decode; VipsImage **format; VipsImage **size; if( VIPS_OBJECT_CLASS( vips_bandary_parent_class )->build( object ) ) return( -1 ); if( bandary->n <= 0 ) { vips_error( object_class->nickname, "%s", _( "no input images" ) ); return( -1 ); } if( bandary->n > MAX_INPUT_IMAGES ) { vips_error( object_class->nickname, "%s", _( "too many input images" ) ); return( -1 ); } decode = (VipsImage **) vips_object_local_array( object, bandary->n ); format = (VipsImage **) vips_object_local_array( object, bandary->n ); size = (VipsImage **) vips_object_local_array( object, bandary->n ); for( i = 0; i < bandary->n; i++ ) if( vips_image_decode( bandary->in[i], &decode[i] ) ) return( -1 ); if( vips__formatalike_vec( decode, format, bandary->n ) || vips__sizealike_vec( format, size, bandary->n ) ) return( -1 ); bandary->ready = size; if( vips_image_pipeline_array( conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, bandary->ready ) ) return( -1 ); conversion->out->Bands = bandary->out_bands; if( class->format_table ) conversion->out->BandFmt = class->format_table[bandary->ready[0]->BandFmt]; if( vips_image_generate( conversion->out, vips_start_many, vips_bandary_gen, vips_stop_many, bandary->ready, bandary ) ) return( -1 ); return( 0 ); }
int vips_object_build( VipsObject *object ) { VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS( object ); #ifdef DEBUG printf( "vips_object_build: " ); vips_object_print( object ); #endif /*DEBUG*/ return( object_class->build( object ) ); }
static int vips_similarity_build( VipsObject *object ) { VipsResample *resample = VIPS_RESAMPLE( object ); VipsSimilarity *similarity = (VipsSimilarity *) object; VipsImage **t = (VipsImage **) vips_object_local_array( object, 4 ); if( VIPS_OBJECT_CLASS( vips_similarity_parent_class )->build( object ) ) return( -1 ); /* Use vips_reduce(), if we can. */ if( similarity->interpolate && strcmp( VIPS_OBJECT_GET_CLASS( similarity->interpolate )-> nickname, "bicubic" ) == 0 && similarity->angle == 0.0 && similarity->idx == 0.0 && similarity->idy == 0.0 && similarity->odx == 0.0 && similarity->ody == 0.0 ) { if( vips_reduce( resample->in, &t[0], 1.0 / similarity->scale, 1.0 / similarity->scale, NULL ) ) return( -1 ); } else { double a = similarity->scale * cos( VIPS_RAD( similarity->angle ) ); double b = similarity->scale * -sin( VIPS_RAD( similarity->angle ) ); double c = -b; double d = a; if( vips_affine( resample->in, &t[0], a, b, c, d, "interpolate", similarity->interpolate, "odx", similarity->odx, "ody", similarity->ody, "idx", similarity->idx, "idy", similarity->idy, NULL ) ) return( -1 ); } if( vips_image_write( t[0], resample->out ) ) return( -1 ); return( 0 ); }
// just g_object_set_property(), except we allow set enum from string static void set_property( VipsObject *object, const char *name, const GValue *value ) { VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS( object ); GType type = G_VALUE_TYPE( value ); GParamSpec *pspec; VipsArgumentClass *argument_class; VipsArgumentInstance *argument_instance; if( vips_object_get_argument( object, name, &pspec, &argument_class, &argument_instance ) ) { g_warning( "%s", vips_error_buffer() ); vips_error_clear(); return; } if( G_IS_PARAM_SPEC_ENUM( pspec ) && type == G_TYPE_STRING ) { GType pspec_type = G_PARAM_SPEC_VALUE_TYPE( pspec ); int enum_value; GValue value2 = { 0 }; if( (enum_value = vips_enum_from_nick( object_class->nickname, pspec_type, g_value_get_string( value ) )) < 0 ) { g_warning( "%s", vips_error_buffer() ); vips_error_clear(); return; } g_value_init( &value2, pspec_type ); g_value_set_enum( &value2, enum_value ); g_object_set_property( G_OBJECT( object ), name, &value2 ); g_value_unset( &value2 ); } else g_object_set_property( G_OBJECT( object ), name, value ); }
static VipsImage * thumbnail_shrink( VipsObject *process, VipsImage *in, VipsInterpolate *interp, VipsImage *sharpen ) { VipsImage **t = (VipsImage **) vips_object_local_array( process, 10 ); VipsInterpretation interpretation = linear_processing ? VIPS_INTERPRETATION_XYZ : VIPS_INTERPRETATION_sRGB; int shrink; double residual; int tile_width; int tile_height; int nlines; /* RAD needs special unpacking. */ if( in->Coding == VIPS_CODING_RAD ) { vips_info( "vipsthumbnail", "unpacking Rad to float" ); /* rad is scrgb. */ if( vips_rad2float( in, &t[0], NULL ) ) return( NULL ); in = t[0]; } /* In linear mode, we import right at the start. * * This is only going to work for images in device space. If you have * an image in PCS which also has an attached profile, strange things * will happen. */ if( linear_processing && in->Coding == VIPS_CODING_NONE && (in->BandFmt == VIPS_FORMAT_UCHAR || in->BandFmt == VIPS_FORMAT_USHORT) && (vips_image_get_typeof( in, VIPS_META_ICC_NAME ) || import_profile) ) { if( vips_image_get_typeof( in, VIPS_META_ICC_NAME ) ) vips_info( "vipsthumbnail", "importing with embedded profile" ); else vips_info( "vipsthumbnail", "importing with profile %s", import_profile ); if( vips_icc_import( in, &t[1], "input_profile", import_profile, "embedded", TRUE, "pcs", VIPS_PCS_XYZ, NULL ) ) return( NULL ); in = t[1]; } /* To the processing colourspace. This will unpack LABQ as well. */ vips_info( "vipsthumbnail", "converting to processing space %s", vips_enum_nick( VIPS_TYPE_INTERPRETATION, interpretation ) ); if( vips_colourspace( in, &t[2], interpretation, NULL ) ) return( NULL ); in = t[2]; shrink = calculate_shrink( in, &residual ); vips_info( "vipsthumbnail", "integer shrink by %d", shrink ); if( vips_shrink( in, &t[3], shrink, shrink, NULL ) ) return( NULL ); in = t[3]; /* 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. */ vips_get_tile_size( in, &tile_width, &tile_height, &nlines ); if( vips_tilecache( in, &t[4], "tile_width", in->Xsize, "tile_height", 10, "max_tiles", (nlines * 2) / 10, "access", VIPS_ACCESS_SEQUENTIAL, "threaded", TRUE, NULL ) || vips_affine( t[4], &t[5], residual, 0, 0, residual, "interpolate", interp, NULL ) ) return( NULL ); in = t[5]; vips_info( "vipsthumbnail", "residual scale by %g", residual ); vips_info( "vipsthumbnail", "%s interpolation", VIPS_OBJECT_GET_CLASS( interp )->nickname ); /* Colour management. * * In linear mode, just export. In device space mode, do a combined * import/export to transform to the target space. */ if( linear_processing ) { if( export_profile || vips_image_get_typeof( in, VIPS_META_ICC_NAME ) ) { vips_info( "vipsthumbnail", "exporting to device space with a profile" ); if( vips_icc_export( in, &t[7], "output_profile", export_profile, NULL ) ) return( NULL ); in = t[7]; } else { vips_info( "vipsthumbnail", "converting to sRGB" ); if( vips_colourspace( in, &t[6], VIPS_INTERPRETATION_sRGB, NULL ) ) return( NULL ); in = t[6]; } } else if( export_profile && (vips_image_get_typeof( in, VIPS_META_ICC_NAME ) || import_profile) ) { if( vips_image_get_typeof( in, VIPS_META_ICC_NAME ) ) vips_info( "vipsthumbnail", "importing with embedded profile" ); else vips_info( "vipsthumbnail", "importing with profile %s", import_profile ); vips_info( "vipsthumbnail", "exporting with profile %s", export_profile ); if( vips_icc_transform( in, &t[6], export_profile, "input_profile", import_profile, "embedded", TRUE, NULL ) ) return( NULL ); in = t[6]; } /* If we are upsampling, don't sharpen, since nearest looks dumb * sharpened. */ if( shrink >= 1 && residual <= 1.0 && sharpen ) { vips_info( "vipsthumbnail", "sharpening thumbnail" ); if( vips_conv( in, &t[8], sharpen, NULL ) ) return( NULL ); in = t[8]; } if( delete_profile && vips_image_get_typeof( in, VIPS_META_ICC_NAME ) ) { vips_info( "vipsthumbnail", "deleting profile from output image" ); if( !vips_image_remove( in, VIPS_META_ICC_NAME ) ) return( NULL ); } return( in ); }
static int vips_similarity_build( VipsObject *object ) { VipsResample *resample = VIPS_RESAMPLE( object ); VipsSimilarity *similarity = (VipsSimilarity *) object; VipsImage **t = (VipsImage **) vips_object_local_array( object, 4 ); gboolean handled; if( VIPS_OBJECT_CLASS( vips_similarity_parent_class )->build( object ) ) return( -1 ); handled = FALSE; /* Use vips_reduce(), if we can. */ if( similarity->interpolate && similarity->angle == 0.0 && similarity->idx == 0.0 && similarity->idy == 0.0 && similarity->odx == 0.0 && similarity->ody == 0.0 ) { const char *nickname = VIPS_OBJECT_GET_CLASS( similarity->interpolate )->nickname; int i; for( i = 0; i < VIPS_NUMBER( vips_similarity_kernel ); i++ ) { VipsInterpolateKernel *ik = &vips_similarity_kernel[i]; if( strcmp( nickname, ik->nickname ) == 0 ) { if( vips_reduce( resample->in, &t[0], 1.0 / similarity->scale, 1.0 / similarity->scale, "kernel", ik->kernel, NULL ) ) return( -1 ); handled = TRUE; break; } } } if( !handled ) { double a = similarity->scale * cos( VIPS_RAD( similarity->angle ) ); double b = similarity->scale * -sin( VIPS_RAD( similarity->angle ) ); double c = -b; double d = a; if( vips_affine( resample->in, &t[0], a, b, c, d, "interpolate", similarity->interpolate, "odx", similarity->odx, "ody", similarity->ody, "idx", similarity->idx, "idy", similarity->idy, NULL ) ) return( -1 ); } if( vips_image_write( t[0], resample->out ) ) return( -1 ); return( 0 ); }