static int write_blank( VipsForeignSaveDz *dz ) { VipsImage *x, *t; int n; VipsArea *ones; double *d; int i; void *buf; size_t len; GsfOutput *out; if( vips_black( &x, dz->tile_size, dz->tile_size, NULL ) ) return( -1 ); vips_area_get_data( (VipsArea *) dz->background, NULL, &n, NULL, NULL ); ones = vips_area_new_array( G_TYPE_DOUBLE, sizeof( double ), n ); d = (double *) vips_area_get_data( ones, NULL, NULL, NULL, NULL ); for( i = 0; i < n; i++ ) d[i] = 1.0; if( vips_linear( x, &t, d, (double *) vips_area_get_data( (VipsArea *) dz->background, NULL, NULL, NULL, NULL ), n, NULL ) ) { vips_area_unref( ones ); g_object_unref( x ); return( -1 ); } vips_area_unref( ones ); g_object_unref( x ); x = t; if( vips_pngsave_buffer( x, &buf, &len, NULL ) ) { g_object_unref( x ); return( -1 ); } g_object_unref( x ); out = vips_gsf_path( dz->tree, "blank.png", NULL ); gsf_output_write( out, len, buf ); gsf_output_close( out ); g_object_unref( out ); g_free( buf ); return( 0 ); }
/* Calculate a pixel for an image from a vec of double. Valid while im is * valid. imag can be NULL, meaning all zero for the imaginary component. */ VipsPel * vips__vector_to_ink( const char *domain, VipsImage *im, double *real, double *imag, int n ) { /* Run our pipeline relative to this. */ VipsImage *context = vips_image_new(); VipsImage **t = (VipsImage **) vips_object_local_array( VIPS_OBJECT( context ), 6 ); VipsBandFormat format; int bands; double *ones; VipsPel *result; int i; #ifdef VIPS_DEBUG printf( "vips__vector_to_ink: starting\n" ); #endif /*VIPS_DEBUG*/ vips_image_decode_predict( im, &bands, &format ); ones = VIPS_ARRAY( im, n, double ); for( i = 0; i < n; i++ ) ones[i] = 1.0; /* Cast vec to match the decoded image. */ if( vips_black( &t[1], 1, 1, "bands", bands, NULL ) || vips_linear( t[1], &t[2], ones, real, n, NULL ) || vips_cast( t[2], &t[3], format, NULL ) ) { g_object_unref( context ); return( NULL ); } /* And now recode the vec to match the original im. */ if( vips_image_encode( t[3], &t[4], im->Coding ) || !(t[5] = vips_image_new_memory()) || vips_image_write( t[4], t[5] ) ) { g_object_unref( context ); return( NULL ); } if( !(result = VIPS_ARRAY( im, VIPS_IMAGE_SIZEOF_PEL( t[5] ), VipsPel )) ) { g_object_unref( context ); return( NULL ); } g_assert( VIPS_IMAGE_SIZEOF_PEL( t[5] ) == VIPS_IMAGE_SIZEOF_PEL( im ) ); memcpy( result, t[5]->data, VIPS_IMAGE_SIZEOF_PEL( im ) ); g_object_unref( context ); #ifdef VIPS_DEBUG { int i; printf( "vips__vector_to_ink:\n" ); printf( "\t(real, imag) = " ); for( i = 0; i < n; i++ ) printf( "(%g, %g) ", real[i], imag ? imag[i] : 0 ); printf( "\n" ); printf( "\tink = " ); for( i = 0; i < VIPS_IMAGE_SIZEOF_PEL( im ); i++ ) printf( "%d ", result[i] ); printf( "\n" ); } #endif /*VIPS_DEBUG*/ return( result ); }
/* Make a pair of vector constants into a set of formatted pixels. bands can * be 3 while n is 1, meaning expand the constant to the number of bands. * imag can be NULL, meaning all zero for the imaginary component. */ VipsPel * vips__vector_to_pels( const char *domain, int bands, VipsBandFormat format, VipsCoding coding, double *real, double *imag, int n ) { /* Run our pipeline relative to this. */ VipsImage *context = vips_image_new(); VipsImage **t = (VipsImage **) vips_object_local_array( VIPS_OBJECT( context ), 8 ); VipsImage *in; double *ones; VipsPel *result; int i; #ifdef VIPS_DEBUG printf( "vips__vector_to_pels: starting\n" ); #endif /*VIPS_DEBUG*/ ones = VIPS_ARRAY( context, n, double ); for( i = 0; i < n; i++ ) ones[i] = 1.0; /* Make the real and imaginary parts. */ if( vips_black( &t[0], 1, 1, "bands", bands, NULL ) || vips_linear( t[0], &t[1], ones, real, n, NULL ) ) { g_object_unref( context ); return( NULL ); } in = t[1]; if( imag ) { if( vips_black( &t[2], 1, 1, "bands", bands, NULL ) || vips_linear( t[2], &t[3], ones, imag, n, NULL ) || vips_complexform( in, t[3], &t[4], NULL ) ) { g_object_unref( context ); return( NULL ); } in = t[4]; } /* Cast to the output type and coding. */ if( vips_cast( in, &t[5], format, NULL ) || vips_image_encode( t[5], &t[6], coding ) ) { g_object_unref( context ); return( NULL ); } in = t[6]; /* Write to memory, copy to output buffer. */ if( !(t[7] = vips_image_new_memory()) || vips_image_write( in, t[7] ) ) { g_object_unref( context ); return( NULL ); } in = t[7]; if( !(result = VIPS_ARRAY( NULL, VIPS_IMAGE_SIZEOF_PEL( in ), VipsPel )) ) { g_object_unref( context ); return( NULL ); } memcpy( result, in->data, VIPS_IMAGE_SIZEOF_PEL( in ) ); #ifdef VIPS_DEBUG { int i; printf( "vips__vector_to_ink:\n" ); printf( "\t(real, imag) = " ); for( i = 0; i < n; i++ ) printf( "(%g, %g) ", real[i], imag ? imag[i] : 0 ); printf( "\n" ); printf( "\tink = " ); for( i = 0; i < VIPS_IMAGE_SIZEOF_PEL( in ); i++ ) printf( "%d ", result[i] ); printf( "\n" ); } #endif /*VIPS_DEBUG*/ g_object_unref( context ); return( result ); }
static int vips_smartcrop_attention( VipsSmartcrop *smartcrop, VipsImage *in, int *left, int *top ) { /* From smartcrop.js. */ static double skin_vector[] = {-0.78, -0.57, -0.44}; static double ones[] = {1.0, 1.0, 1.0}; VipsImage **t = (VipsImage **) vips_object_local_array( VIPS_OBJECT( smartcrop ), 24 ); double hscale; double vscale; double sigma; double max; int x_pos; int y_pos; /* The size we shrink to gives the precision with which we can place * the crop */ hscale = 32.0 / in->Xsize; vscale = 32.0 / in->Ysize; sigma = VIPS_MAX( sqrt( pow( smartcrop->width * hscale, 2 ) + pow( smartcrop->height * vscale, 2 ) ) / 10, 1.0 ); if ( vips_resize( in, &t[17], hscale, "vscale", vscale, NULL ) ) return( -1 ); /* Simple edge detect. */ if( !(t[21] = vips_image_new_matrixv( 3, 3, 0.0, -1.0, 0.0, -1.0, 4.0, -1.0, 0.0, -1.0, 0.0 )) ) return( -1 ); /* Convert to XYZ and just use the first three bands. */ if( vips_colourspace( t[17], &t[0], VIPS_INTERPRETATION_XYZ, NULL ) || vips_extract_band( t[0], &t[1], 0, "n", 3, NULL ) ) return( -1 ); /* Edge detect on Y. */ if( vips_extract_band( t[1], &t[2], 1, NULL ) || vips_conv( t[2], &t[3], t[21], "precision", VIPS_PRECISION_INTEGER, NULL ) || vips_linear1( t[3], &t[4], 5.0, 0.0, NULL ) || vips_abs( t[4], &t[14], NULL ) ) return( -1 ); /* Look for skin colours. Taken from smartcrop.js. */ if( /* Normalise to magnitude of colour in XYZ. */ pythagoras( smartcrop, t[1], &t[5] ) || vips_divide( t[1], t[5], &t[6], NULL ) || /* Distance from skin point. */ vips_linear( t[6], &t[7], ones, skin_vector, 3, NULL ) || pythagoras( smartcrop, t[7], &t[8] ) || /* Rescale to 100 - 0 score. */ vips_linear1( t[8], &t[9], -100.0, 100.0, NULL ) || /* Ignore dark areas. */ vips_more_const1( t[2], &t[10], 5.0, NULL ) || !(t[11] = vips_image_new_from_image1( t[10], 0.0 )) || vips_ifthenelse( t[10], t[9], t[11], &t[15], NULL ) ) return( -1 ); /* Look for saturated areas. */ if( vips_colourspace( t[1], &t[12], VIPS_INTERPRETATION_LAB, NULL ) || vips_extract_band( t[12], &t[13], 1, NULL ) || vips_ifthenelse( t[10], t[13], t[11], &t[16], NULL ) ) return( -1 ); /* Sum, blur and find maxpos. * * The amount of blur is related to the size of the crop * area: how large an area we want to consider for the scoring * function. */ if( vips_sum( &t[14], &t[18], 3, NULL ) || vips_gaussblur( t[18], &t[19], sigma, NULL ) || vips_max( t[19], &max, "x", &x_pos, "y", &y_pos, NULL ) ) return( -1 ); /* Centre the crop over the max. */ *left = VIPS_CLIP( 0, x_pos / hscale - smartcrop->width / 2, in->Xsize - smartcrop->width ); *top = VIPS_CLIP( 0, y_pos / vscale - smartcrop->height / 2, in->Ysize - smartcrop->height ); return( 0 ); }