static int write_dzi( VipsForeignSaveDz *dz ) { GsfOutput *out; char buf[VIPS_PATH_MAX]; char *p; vips_snprintf( buf, VIPS_PATH_MAX, "%s.dzi", dz->basename ); out = vips_gsf_path( dz->tree, buf, NULL ); vips_snprintf( buf, VIPS_PATH_MAX, "%s", dz->suffix + 1 ); if( (p = (char *) vips__find_rightmost_brackets( buf )) ) *p = '\0'; gsf_output_printf( out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ); gsf_output_printf( out, "<Image " "xmlns=\"http://schemas.microsoft.com/deepzoom/2008\"\n" ); gsf_output_printf( out, " Format=\"%s\"\n", buf ); gsf_output_printf( out, " Overlap=\"%d\"\n", dz->overlap ); gsf_output_printf( out, " TileSize=\"%d\"\n", dz->tile_size ); gsf_output_printf( out, " >\n" ); gsf_output_printf( out, " <Size \n" ); gsf_output_printf( out, " Height=\"%d\"\n", dz->layer->height ); gsf_output_printf( out, " Width=\"%d\"\n", dz->layer->width ); gsf_output_printf( out, " />\n" ); gsf_output_printf( out, "</Image>\n" ); (void) gsf_output_close( out ); g_object_unref( out ); return( 0 ); }
/* Make a temporary file name. The format parameter is something like "%s.jpg" * and will be expanded to something like "/tmp/vips-12-34587.jpg". * * You need to free the result. */ char * vips__temp_name( const char *format ) { static int serial = 0; char file[FILENAME_MAX]; char file2[FILENAME_MAX]; char *name; vips_snprintf( file, FILENAME_MAX, "vips-%d-%u", serial++, g_random_int() ); vips_snprintf( file2, FILENAME_MAX, format, file ); name = g_build_filename( vips__temp_dir(), file2, NULL ); /* We could use something like g_mkstemp() to guarantee uniqueness * across processes, but the extra FS calls can be difficult for * selinux. * * g_random_int() should be safe enough -- it's seeded from time(), so * it ought not to collide often -- and on linux at least we never * actually use these filenames in the filesystem anyway. */ return( name ); }
void vips_vector_constant( VipsVector *vector, char *name, int value, int size ) { #ifdef HAVE_ORC char *sname; if( size == 1 ) sname = "b"; else if( size == 2 ) sname = "w"; else if( size == 4 ) sname = "l"; else { printf( "vips_vector_constant: bad constant size\n" ); /* Not really correct, heh. */ sname = "x"; } if( value > 0 ) vips_snprintf( name, 256, "c%d%s", value, sname ); else vips_snprintf( name, 256, "cm%d%s", -value, sname ); if( orc_program_find_var_by_name( vector->program, name ) == -1 ) { orc_program_add_constant( vector->program, size, value, name ); vector->n_constant += 1; } #endif /*HAVE_ORC*/ }
/* Make a temporary file name. The format parameter is something like "%s.jpg" * and will be expanded to something like "/tmp/vips-12-34587.jpg". * * You need to free the result. A real file will also be created, though we * delete it for you. */ char * vips__temp_name( const char *format ) { static int serial = 1; char file[FILENAME_MAX]; char file2[FILENAME_MAX]; char *name; int fd; vips_snprintf( file, FILENAME_MAX, "vips-%d-XXXXXX", serial++ ); vips_snprintf( file2, FILENAME_MAX, format, file ); name = g_build_filename( vips__temp_dir(), file2, NULL ); if( (fd = g_mkstemp( name )) == -1 ) { vips_error( "tempfile", _( "unable to make temporary file %s" ), name ); g_free( name ); return( NULL ); } close( fd ); g_unlink( name ); return( name ); }
/* Guess a value for the install PREFIX. */ static const char * guess_prefix( const char *argv0, const char *name ) { char *prefix; /* Try to guess from argv0. */ if( argv0 ) { if( g_path_is_absolute( argv0 ) ) { /* Must point to our executable. */ if( (prefix = extract_prefix( argv0, name )) ) { #ifdef DEBUG printf( "vips_guess_prefix: found \"%s\" from " "argv0\n", prefix ); #endif /*DEBUG*/ return( prefix ); } } /* Look along path for name. */ if( (prefix = find_file( name )) ) { #ifdef DEBUG printf( "vips_guess_prefix: found \"%s\" from " "PATH\n", prefix ); #endif /*DEBUG*/ return( prefix ); } } #ifdef HAVE_REALPATH /* Try to guess from cwd. Only if this is a relative path, though. No * realpath on winders, but fortunately it seems to always generate * a full path in argv[0]. */ if( !g_path_is_absolute( argv0 ) ) { char full_path[PATH_MAX]; char resolved[PATH_MAX]; vips_snprintf( full_path, PATH_MAX, "%s" G_DIR_SEPARATOR_S "%s", get_current_dir(), argv0 ); if( realpath( full_path, resolved ) ) { if( (prefix = extract_prefix( resolved, name )) ) { #ifdef DEBUG printf( "vips_guess_prefix: found \"%s\" " "from cwd\n", prefix ); #endif /*DEBUG*/ return( prefix ); } } } #endif /*HAVE_REALPATH*/ /* Fall back to the configure-time prefix. */ return( VIPS_PREFIX ); }
/* Search a path for a file ... we overwrite the PATH string passed in. */ static char * scan_path( char *path, const char *name ) { char *p, *q; char *prefix; for( p = path; (q = vips_break_token( p, G_SEARCHPATH_SEPARATOR_S )); p = q ) { char str[PATH_MAX]; /* Form complete path. */ vips_snprintf( str, PATH_MAX, "%s" G_DIR_SEPARATOR_S "%s", p, name ); #ifdef DEBUG printf( "scan_path: looking in \"%s\" for \"%s\"\n", p, name ); #endif /*DEBUG*/ if( vips_existsf( "%s", str ) && (prefix = extract_prefix( str, name )) ) { return( prefix ); } } return( NULL ); }
/* Look for a file along PATH. If we find it, look for an enclosing prefix. */ static char * find_file( const char *name ) { const char *path = g_getenv( "PATH" ); char *prefix; char full_path[PATH_MAX]; if( !path ) return( NULL ); #ifdef DEBUG printf( "vips_guess_prefix: g_getenv( \"PATH\" ) == \"%s\"\n", path ); #endif /*DEBUG*/ #ifdef OS_WIN32 /* Windows always searches '.' first, so prepend cwd to path. */ vips_snprintf( full_path, PATH_MAX, "%s" G_SEARCHPATH_SEPARATOR_S "%s", get_current_dir(), path ); #else /*!OS_WIN32*/ vips_strncpy( full_path, path, PATH_MAX ); #endif /*OS_WIN32*/ if( (prefix = scan_path( full_path, name )) ) return( prefix ); return( NULL ); }
/* Find the prefix part of a dir ... name is the name of this prog from argv0. * * dir name guess prefix * * /home/john/vips-7.6.4/bin/vips-7.6 vips-7.6 /home/john/vips-7.6.4 * /usr/local/bin/ip ip /usr/local * * all other forms ... return NULL. */ static char * extract_prefix( const char *dir, const char *name ) { char edir[PATH_MAX]; char vname[PATH_MAX]; int i; #ifdef DEBUG printf( "extract_prefix: trying for dir = \"%s\", name = \"%s\"\n", dir, name ); #endif /*DEBUG*/ /* Is dir relative? Prefix with cwd. */ if( !g_path_is_absolute( dir ) ) { vips_snprintf( edir, PATH_MAX, "%s" G_DIR_SEPARATOR_S "%s", get_current_dir(), dir ); } else { vips_strncpy( edir, dir, PATH_MAX ); } /* Chop off the trailing prog name, plus the trailing * G_DIR_SEPARATOR_S. */ if( !vips_ispostfix( edir, name ) ) return( NULL ); vips_strncpy( vname, edir, PATH_MAX ); vname[strlen( edir ) - strlen( name ) - 1] = '\0'; /* Remove any "/./", any trailing "/.", any trailing "/". */ for( i = 0; i < (int) strlen( vname ); i++ ) if( vips_isprefix( G_DIR_SEPARATOR_S "." G_DIR_SEPARATOR_S, vname + i ) ) memcpy( vname + i, vname + i + 2, strlen( vname + i + 2 ) + 1 ); if( vips_ispostfix( vname, G_DIR_SEPARATOR_S "." ) ) vname[strlen( vname ) - 2] = '\0'; if( vips_ispostfix( vname, G_DIR_SEPARATOR_S ) ) vname[strlen( vname ) - 1] = '\0'; #ifdef DEBUG printf( "extract_prefix: canonicalised path = \"%s\"\n", vname ); #endif /*DEBUG*/ /* Ought to be a "/bin" at the end now. */ if( !vips_ispostfix( vname, G_DIR_SEPARATOR_S "bin" ) ) return( NULL ); vname[strlen( vname ) - strlen( G_DIR_SEPARATOR_S "bin" )] = '\0'; #ifdef DEBUG printf( "extract_prefix: found \"%s\"\n", vname ); #endif /*DEBUG*/ return( vips_strdup( NULL, vname ) ); }
/* Transform an area to a G_TYPE_STRING. */ static void transform_area_g_string( const GValue *src_value, GValue *dest_value ) { VipsArea *area; char buf[256]; area = g_value_get_boxed( src_value ); vips_snprintf( buf, 256, "VIPS_TYPE_AREA, count = %d, data = %p", area->count, area->data ); g_value_set_string( dest_value, buf ); }
/* Transform a blob to a G_TYPE_STRING. */ static void transform_blob_g_string( const GValue *src_value, GValue *dest_value ) { void *blob; size_t blob_length; char buf[256]; blob = vips_value_get_blob( src_value, &blob_length ); vips_snprintf( buf, 256, "VIPS_TYPE_BLOB, data = %p, length = %zd", blob, blob_length ); g_value_set_string( dest_value, buf ); }
/* Load all plugins in a directory ... look for '.plg' suffix. Error if we had * any probs. */ static int vips_load_plugins( const char *fmt, ... ) { va_list ap; char dir_name[VIPS_PATH_MAX]; GDir *dir; const char *name; int result; /* Silently succeed if we can't do modules. */ if( !g_module_supported() ) return( 0 ); va_start( ap, fmt ); (void) vips_vsnprintf( dir_name, VIPS_PATH_MAX - 1, fmt, ap ); va_end( ap ); #ifdef DEBUG printf( "vips_load_plugins: searching \"%s\"\n", dir_name ); #endif /*DEBUG*/ if( !(dir = g_dir_open( dir_name, 0, NULL )) ) /* Silent success for dir not there. */ return( 0 ); result = 0; while( (name = g_dir_read_name( dir )) ) if( vips_ispostfix( name, ".plg" ) ) { char path[VIPS_PATH_MAX]; GModule *module; vips_snprintf( path, VIPS_PATH_MAX - 1, "%s" G_DIR_SEPARATOR_S "%s", dir_name, name ); #ifdef DEBUG printf( "vips_load_plugins: loading \"%s\"\n", path ); #endif /*DEBUG*/ module = g_module_open( path, G_MODULE_BIND_LAZY ); if( !module ) { vips_warn( "vips_init", _( "unable to load \"%s\" -- %s" ), path, g_module_error() ); result = -1; } } g_dir_close( dir ); return( result ); }
static void * vips_foreign_load_nifti_set( const char *name, GValue *value, glong offset, void *a, void *b ) { nifti_image *nim = (nifti_image *) a; VipsImage *out = VIPS_IMAGE( b ); char vips_name[256]; vips_gvalue_read( value, (gpointer) nim + offset ); vips_snprintf( vips_name, 256, "nifti-%s", name ); vips_image_set( out, vips_name, value ); return( NULL ); }
void vips_vector_source_scanline( VipsVector *vector, char *name, int line, int size ) { #ifdef HAVE_ORC vips_snprintf( name, 256, "sl%d", line ); if( orc_program_find_var_by_name( vector->program, name ) == -1 ) { int var; var = orc_program_add_source( vector->program, size, name ); vector->sl[vector->n_scanline] = var; vector->line[vector->n_scanline] = line; vector->n_scanline += 1; } #endif /*HAVE_ORC*/ }
/* Given (eg.) "/poop/somefile.png", write @im to the thumbnail name, * (eg.) "/poop/tn_somefile.jpg". */ static int thumbnail_write( VipsImage *im, const char *filename ) { char *file; char *p; char buf[FILENAME_MAX]; char *output_name; file = g_path_get_basename( filename ); /* Remove the suffix from the file portion. */ if( (p = strrchr( file, '.' )) ) *p = '\0'; /* output_format can be an absolute path, in which case we discard the * path from the incoming file. */ vips_snprintf( buf, FILENAME_MAX, output_format, file ); if( g_path_is_absolute( output_format ) ) output_name = g_strdup( buf ); else { char *dir; dir = g_path_get_dirname( filename ); output_name = g_build_filename( dir, buf, NULL ); g_free( dir ); } vips_info( "vipsthumbnail", "thumbnailing %s as %s", filename, output_name ); g_free( file ); if( vips_image_write_to_file( im, output_name, NULL ) ) { g_free( output_name ); return( -1 ); } g_free( output_name ); return( 0 ); }
/* Set the png text data as metadata on the vips image. */ static int vips__set_text( VipsImage *out, int i, const char *key, const char *text ) { char name[256]; if( strcmp( key, "XML:com.adobe.xmp") == 0 ) /* Save as an XMP tag. */ strncpy( name, VIPS_META_XMP_NAME, 256 ); else /* Save as a comment. Some PNGs have EXIF data as * text segments, but the correct way to support this is with * png_get_eXIf_1(). */ vips_snprintf( name, 256, "png-comment-%d-%s", i, key ); vips_image_set_string( out, name, text ); return( 0 ); }
void vips_vector_source_scanline( VipsVector *vector, char *name, int line, int size ) { #ifdef HAVE_ORC vips_snprintf( name, 256, "sl%d", line ); if( orc_program_find_var_by_name( vector->program, name ) == -1 ) { int var; if( !(var = orc_program_add_source( vector->program, size, name )) ) vips_vector_error( vector ); #ifdef DEBUG_TRACE printf( "orc_program_add_source( %s, %d, \"%s\" );\n", vector->unique_name, size, name ); #endif /*DEBUG_TRACE*/ vector->sl[vector->n_scanline] = var; vector->line[vector->n_scanline] = line; vector->n_scanline += 1; } #endif /*HAVE_ORC*/ }
static int vips_fits_get_header( VipsFits *fits, VipsImage *out ) { int status; int bitpix; int width, height, bands, format, type; int keysexist; int i; status = 0; if( fits_get_img_paramll( fits->fptr, 10, &bitpix, &fits->naxis, fits->naxes, &status ) ) { vips_fits_error( status ); return( -1 ); } #ifdef VIPS_DEBUG VIPS_DEBUG_MSG( "naxis = %d\n", fits->naxis ); for( i = 0; i < fits->naxis; i++ ) VIPS_DEBUG_MSG( "%d) %lld\n", i, fits->naxes[i] ); #endif /*VIPS_DEBUG*/ height = 1; bands = 1; switch( fits->naxis ) { /* If you add more dimensions here, adjust data read below. See also * the definition of MAX_DIMENSIONS above. */ case 10: case 9: case 8: case 7: case 6: case 5: case 4: for( i = fits->naxis; i > 3; i-- ) if( fits->naxes[i - 1] != 1 ) { vips_error( "fits", "%s", _( "dimensions above 3 " "must be size 1" ) ); return( -1 ); } case 3: bands = fits->naxes[2]; case 2: height = fits->naxes[1]; case 1: width = fits->naxes[0]; break; default: vips_error( "fits", _( "bad number of axis %d" ), fits->naxis ); return( -1 ); } /* Are we in one-band mode? */ if( fits->band_select != -1 ) bands = 1; /* Get image format. We want the 'raw' format of the image, our caller * can convert using the meta info if they want. */ for( i = 0; i < VIPS_NUMBER( fits2vips_formats ); i++ ) if( fits2vips_formats[i][0] == bitpix ) break; if( i == VIPS_NUMBER( fits2vips_formats ) ) { vips_error( "fits", _( "unsupported bitpix %d\n" ), bitpix ); return( -1 ); } format = fits2vips_formats[i][1]; fits->datatype = fits2vips_formats[i][2]; if( bands == 1 ) { if( format == VIPS_FORMAT_USHORT ) type = VIPS_INTERPRETATION_GREY16; else type = VIPS_INTERPRETATION_B_W; } else if( bands == 3 ) { if( format == VIPS_FORMAT_USHORT ) type = VIPS_INTERPRETATION_RGB16; else type = VIPS_INTERPRETATION_RGB; } else type = VIPS_INTERPRETATION_MULTIBAND; vips_image_pipelinev( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL ); vips_image_init_fields( out, width, height, bands, format, VIPS_CODING_NONE, type, 1.0, 1.0 ); /* Read all keys into meta. */ if( fits_get_hdrspace( fits->fptr, &keysexist, NULL, &status ) ) { vips_fits_error( status ); return( -1 ); } for( i = 0; i < keysexist; i++ ) { char record[81]; char vipsname[100]; if( fits_read_record( fits->fptr, i + 1, record, &status ) ) { vips_fits_error( status ); return( -1 ); } VIPS_DEBUG_MSG( "fits2vips: setting meta on vips image:\n" ); VIPS_DEBUG_MSG( " record == \"%s\"\n", record ); /* FITS lets keys repeat. For example, HISTORY appears many * times, each time with a fresh line of history attached. We * have to include the key index in the vips name we assign. */ vips_snprintf( vipsname, 100, "fits-%d", i ); vips_image_set_string( out, vipsname, record ); } return( 0 ); }
static ReadSlide * readslide_new( const char *filename, VipsImage *out, int level, gboolean autocrop, const char *associated ) { ReadSlide *rslide; int64_t w, h; const char *error; const char *background; const char * const *properties; char *associated_names; if( level && associated ) { vips_error( "openslide2vips", "%s", _( "specify only one of level or associated " "image" ) ); return( NULL ); } rslide = VIPS_NEW( out, ReadSlide ); memset( rslide, 0, sizeof( *rslide ) ); g_signal_connect( out, "close", G_CALLBACK( readslide_destroy_cb ), rslide ); rslide->level = level; rslide->autocrop = autocrop; rslide->associated = g_strdup( associated ); /* Non-crazy defaults, override below if we can. */ rslide->tile_width = 256; rslide->tile_height = 256; rslide->osr = openslide_open( filename ); if( rslide->osr == NULL ) { vips_error( "openslide2vips", "%s", _( "unsupported slide format" ) ); return( NULL ); } error = openslide_get_error( rslide->osr ); if( error ) { vips_error( "openslide2vips", _( "opening slide: %s" ), error ); return( NULL ); } if( level < 0 || level >= openslide_get_level_count( rslide->osr ) ) { vips_error( "openslide2vips", "%s", _( "invalid slide level" ) ); return( NULL ); } if( associated && check_associated_image( rslide->osr, associated ) ) return( NULL ); if( associated ) { openslide_get_associated_image_dimensions( rslide->osr, associated, &w, &h ); vips_image_set_string( out, "slide-associated-image", associated ); vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL ); } else { char buf[256]; const char *value; openslide_get_level_dimensions( rslide->osr, level, &w, &h ); rslide->downsample = openslide_get_level_downsample( rslide->osr, level ); vips_image_set_int( out, "slide-level", level ); vips_image_pipelinev( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL ); /* Try to get tile width/height. An undocumented, experimental * feature. */ vips_snprintf( buf, 256, "openslide.level[%d].tile-width", level ); if( (value = openslide_get_property_value( rslide->osr, buf )) ) rslide->tile_width = atoi( value ); vips_snprintf( buf, 256, "openslide.level[%d].tile-height", level ); if( (value = openslide_get_property_value( rslide->osr, buf )) ) rslide->tile_height = atoi( value ); if( value ) VIPS_DEBUG_MSG( "readslide_new: found tile-size\n" ); /* Some images have a bounds in the header. Crop to * that if autocrop is set. */ if( rslide->autocrop ) if( !get_bounds( rslide->osr, &rslide->bounds ) ) rslide->autocrop = FALSE; if( rslide->autocrop ) { VipsRect image; rslide->bounds.left /= rslide->downsample; rslide->bounds.top /= rslide->downsample; rslide->bounds.width /= rslide->downsample; rslide->bounds.height /= rslide->downsample; /* Clip against image size. */ image.left = 0; image.top = 0; image.width = w; image.height = h; vips_rect_intersectrect( &rslide->bounds, &image, &rslide->bounds ); /* If we've clipped to nothing, ignore bounds. */ if( vips_rect_isempty( &rslide->bounds ) ) rslide->autocrop = FALSE; } if( rslide->autocrop ) { w = rslide->bounds.width; h = rslide->bounds.height; } } rslide->bg = 0xffffff; if( (background = openslide_get_property_value( rslide->osr, OPENSLIDE_PROPERTY_NAME_BACKGROUND_COLOR )) ) rslide->bg = strtoul( background, NULL, 16 ); if( w <= 0 || h <= 0 || rslide->downsample < 0 ) { vips_error( "openslide2vips", _( "getting dimensions: %s" ), openslide_get_error( rslide->osr ) ); return( NULL ); } if( w > INT_MAX || h > INT_MAX ) { vips_error( "openslide2vips", "%s", _( "image dimensions overflow int" ) ); return( NULL ); } if( !rslide->autocrop ) { rslide->bounds.left = 0; rslide->bounds.top = 0; rslide->bounds.width = w; rslide->bounds.height = h; } vips_image_init_fields( out, w, h, 4, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_RGB, 1.0, 1.0 ); for( properties = openslide_get_property_names( rslide->osr ); *properties != NULL; properties++ ) vips_image_set_string( out, *properties, openslide_get_property_value( rslide->osr, *properties ) ); associated_names = g_strjoinv( ", ", (char **) openslide_get_associated_image_names( rslide->osr ) ); vips_image_set_string( out, "slide-associated-images", associated_names ); VIPS_FREE( associated_names ); return( rslide ); }
static Read * read_new( const char *filename, VipsImage *im, gboolean all_frames, const char *density, int page ) { Read *read; static int inited = 0; if( !inited ) { #ifdef HAVE_MAGICKCOREGENESIS MagickCoreGenesis( vips_get_argv0(), MagickFalse ); #else /*!HAVE_MAGICKCOREGENESIS*/ InitializeMagick( "" ); #endif /*HAVE_MAGICKCOREGENESIS*/ inited = 1; } if( !(read = VIPS_NEW( im, Read )) ) return( NULL ); read->filename = filename ? g_strdup( filename ) : NULL; read->all_frames = all_frames; read->page = page; read->im = im; read->image = NULL; read->image_info = CloneImageInfo( NULL ); GetExceptionInfo( &read->exception ); read->n_frames = 0; read->frames = NULL; read->frame_height = 0; read->lock = vips_g_mutex_new(); g_signal_connect( im, "close", G_CALLBACK( read_close ), read ); if( !read->image_info ) return( NULL ); if( filename ) vips_strncpy( read->image_info->filename, filename, MaxTextExtent ); /* Canvas resolution for rendering vector formats like SVG. */ VIPS_SETSTR( read->image_info->density, density ); #ifdef HAVE_SETIMAGEOPTION /* When reading DICOM images, we want to ignore any * window_center/_width setting, since it may put pixels outside the * 0-65535 range and lose data. * * These window settings are attached as vips metadata, so our caller * can interpret them if it wants. */ SetImageOption( read->image_info, "dcm:display-range", "reset" ); #endif /*HAVE_SETIMAGEOPTION*/ if( !all_frames ) { #ifdef HAVE_NUMBER_SCENES /* I can't find docs for these fields, but this seems to work. */ char page[256]; read->image_info->scene = read->page; read->image_info->number_scenes = 1; /* Some IMs must have the string version set as well. */ vips_snprintf( page, 256, "%d", read->page ); read->image_info->scenes = strdup( page ); #else /*!HAVE_NUMBER_SCENES*/ /* This works with GM 1.2.31 and probably others. */ read->image_info->subimage = read->page; read->image_info->subrange = 1; #endif } #ifdef DEBUG printf( "magick2vips: read_new: %s\n", read->filename ); #endif /*DEBUG*/ return( read ); }
/* Generate code for a section of the mask. first is the index we start * at, we set last to the index of the last one we use before we run * out of intermediates / constants / parameters / sources or mask * coefficients. * * 0 for success, -1 on error. */ static int vips_reducev_compile_section( VipsReducev *reducev, Pass *pass, gboolean first ) { VipsVector *v; int i; #ifdef DEBUG_COMPILE printf( "starting pass %d\n", pass->first ); #endif /*DEBUG_COMPILE*/ pass->vector = v = vips_vector_new( "reducev", 1 ); /* We have two destinations: the final output image (8-bit) and the * intermediate buffer if this is not the final pass (16-bit). */ pass->d2 = vips_vector_destination( v, "d2", 2 ); /* "r" is the array of sums from the previous pass (if any). */ pass->r = vips_vector_source_name( v, "r", 2 ); /* The value we fetch from the image, the accumulated sum. */ TEMP( "value", 2 ); TEMP( "sum", 2 ); /* Init the sum. If this is the first pass, it's a constant. If this * is a later pass, we have to init the sum from the result * of the previous pass. */ if( first ) { char c0[256]; CONST( c0, 0, 2 ); ASM2( "loadpw", "sum", c0 ); } else ASM2( "loadw", "sum", "r" ); for( i = pass->first; i < reducev->n_point; i++ ) { char source[256]; char coeff[256]; SCANLINE( source, i, 1 ); /* This mask coefficient. */ vips_snprintf( coeff, 256, "p%d", i ); pass->p[pass->n_param] = PARAM( coeff, 2 ); pass->n_param += 1; if( pass->n_param >= MAX_PARAM ) return( -1 ); /* Mask coefficients are 2.6 bits fixed point. We need to hold * about -0.5 to 1.0, so -2 to +1.999 is as close as we can * get. * * We need a signed multiply, so the image pixel needs to * become a signed 16-bit value. We know only the bottom 8 bits * of the image and coefficient are interesting, so we can take * the bottom bits of a 16x16->32 multiply. * * We accumulate the signed 16-bit result in sum. */ ASM2( "convubw", "value", source ); ASM3( "mullw", "value", "value", coeff ); ASM3( "addssw", "sum", "sum", "value" ); /* We've used this coeff. */ pass->last = i; if( vips_vector_full( v ) ) break; /* orc 0.4.24 and earlier hate more than about five lines at * once :( */ if( i - pass->first > 3 ) break; } /* If this is the end of the mask, we write the 8-bit result to the * image, otherwise write the 16-bit intermediate to our temp buffer. */ if( pass->last >= reducev->n_point - 1 ) { char c32[256]; char c6[256]; char c0[256]; char c255[256]; CONST( c32, 32, 2 ); ASM3( "addw", "sum", "sum", c32 ); CONST( c6, 6, 2 ); ASM3( "shrsw", "sum", "sum", c6 ); /* You'd think "convsuswb", convert signed 16-bit to unsigned * 8-bit with saturation, would be quicker, but it's a lot * slower. */ CONST( c0, 0, 2 ); ASM3( "maxsw", "sum", c0, "sum" ); CONST( c255, 255, 2 ); ASM3( "minsw", "sum", c255, "sum" ); ASM2( "convwb", "d1", "sum" ); } else ASM2( "copyw", "d2", "sum" ); if( !vips_vector_compile( v ) ) return( -1 ); #ifdef DEBUG_COMPILE printf( "done coeffs %d to %d\n", pass->first, pass->last ); vips_vector_print( v ); #endif /*DEBUG_COMPILE*/ return( 0 ); }
/** * vips_init: * @argv0: name of application * * vips_init() starts up the world of VIPS. You should call this on * program startup before using any other VIPS operations. If you do not call * vips_init(), VIPS will call it for you when you use your first VIPS * operation, but * it may not be able to get hold of @argv0 and VIPS may therefore be unable * to find its data files. It is much better to call this function yourself. * * vips_init() does approximately the following: * * <itemizedlist> * <listitem> * <para>initialises any libraries that VIPS is using, including GObject * and the threading system, if neccessary</para> * </listitem> * <listitem> * <para>guesses where the VIPS data files are and sets up * internationalisation --- see vips_guess_prefix() * </para> * </listitem> * <listitem> * <para>creates the main vips types, including VipsImage and friends * </para> * </listitem> * <listitem> * <para>loads any plugins from $libdir/vips-x.y, where x and y are the * major and minor version numbers for this VIPS. * </para> * </listitem> * </itemizedlist> * * Example: * * |[ * int main( int argc, char **argv ) * { * if( vips_init( argv[0] ) ) * vips_error_exit( "unable to start VIPS" ); * * vips_shutdown(); * * return( 0 ); * } * ]| * * See also: vips_shutdown(), vips_get_option_group(), vips_version(), * vips_guess_prefix(), vips_guess_libdir(). * * Returns: 0 on success, -1 otherwise */ int vips_init( const char *argv0 ) { extern GType vips_system_get_type( void ); static gboolean started = FALSE; static gboolean done = FALSE; char *prgname; const char *prefix; const char *libdir; char name[256]; /* Two stage done handling: 'done' means we've completed, 'started' * means we're currently initialising. Use this to prevent recursive * invocation. */ if( done ) /* Called more than once, we succeeded, just return OK. */ return( 0 ); if( started ) /* Recursive invocation, something has broken horribly. * Hopefully the first init will handle it. */ return( 0 ); started = TRUE; #ifdef NEED_TYPE_INIT /* Before glib 2.36 you have to call this on startup. */ g_type_init(); #endif /*NEED_TYPE_INIT*/ /* Older glibs need this. */ #ifndef HAVE_THREAD_NEW if( !g_thread_supported() ) g_thread_init( NULL ); #endif if( !vips__global_lock ) vips__global_lock = vips_g_mutex_new(); VIPS_SETSTR( vips__argv0, argv0 ); prgname = g_path_get_basename( argv0 ); g_set_prgname( prgname ); g_free( prgname ); /* Try to discover our prefix. */ if( !(prefix = vips_guess_prefix( argv0, "VIPSHOME" )) || !(libdir = vips_guess_libdir( argv0, "VIPSHOME" )) ) return( -1 ); /* Get i18n .mo files from $VIPSHOME/share/locale/. */ vips_snprintf( name, 256, "%s" G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S "locale", prefix ); bindtextdomain( GETTEXT_PACKAGE, name ); bind_textdomain_codeset( GETTEXT_PACKAGE, "UTF-8" ); /* Default info setting from env. */ if( g_getenv( "IM_INFO" ) ) vips__info = 1; /* Register base vips types. */ (void) vips_image_get_type(); (void) vips_region_get_type(); vips__meta_init_types(); vips__interpolate_init(); im__format_init(); /* Start up operator cache. */ vips__cache_init(); /* Start up packages. */ (void) vips_system_get_type(); vips_arithmetic_operation_init(); vips_conversion_operation_init(); vips_create_operation_init(); vips_foreign_operation_init(); vips_resample_operation_init(); vips_colour_operation_init(); vips_histogram_operation_init(); vips_convolution_operation_init(); /* Load up any plugins in the vips libdir. We don't error on failure, * it's too annoying to have VIPS refuse to start because of a broken * plugin. */ if( im_load_plugins( "%s/vips-%d.%d", libdir, VIPS_MAJOR_VERSION, VIPS_MINOR_VERSION ) ) { vips_warn( "vips_init", "%s", vips_error_buffer() ); vips_error_clear(); } /* Also load from libdir. This is old and slightly broken behaviour * :-( kept for back compat convenience. */ if( im_load_plugins( "%s", libdir ) ) { vips_warn( "vips_init", "%s", vips_error_buffer() ); vips_error_clear(); } /* Build classes which wrap old vips7 operations. */ vips__init_wrap7_classes(); /* Start up the buffer cache. */ vips__buffer_init(); /* Get the run-time compiler going. */ vips_vector_init(); /* Register vips_shutdown(). This may well not get called and many * platforms don't support it anyway. */ #ifdef HAVE_ATEXIT atexit( vips_shutdown ); #endif /*HAVE_ATEXIT*/ done = TRUE; return( 0 ); }
int vips_init( const char *argv0 ) { extern GType vips_system_get_type( void ); static gboolean started = FALSE; static gboolean done = FALSE; char *prgname; const char *prefix; const char *libdir; char name[256]; /* Two stage done handling: 'done' means we've completed, 'started' * means we're currently initialising. Use this to prevent recursive * invocation. */ if( done ) /* Called more than once, we succeeded, just return OK. */ return( 0 ); if( started ) /* Recursive invocation, something has broken horribly. * Hopefully the first init will handle it. */ return( 0 ); started = TRUE; #ifdef HAVE_TYPE_INIT /* Before glib 2.36 you have to call this on startup. */ g_type_init(); #endif /*HAVE_TYPE_INIT*/ /* Older glibs need this. */ #ifndef HAVE_THREAD_NEW if( !g_thread_supported() ) g_thread_init( NULL ); #endif /* This does an unsynchronised static hash table init on first call -- * we have to make sure we do this single-threaded. See: * https://github.com/openslide/openslide/issues/161 */ (void) g_get_language_names(); if( !vips__global_lock ) vips__global_lock = vips_g_mutex_new(); VIPS_SETSTR( vips__argv0, argv0 ); prgname = g_path_get_basename( argv0 ); g_set_prgname( prgname ); g_free( prgname ); vips__thread_profile_attach( "main" ); /* We can't do VIPS_GATE_START() until command-line processing * happens, since vips__thread_profile may not be set yet. Call * directly. */ vips__thread_gate_start( "init: main" ); vips__thread_gate_start( "init: startup" ); /* Try to discover our prefix. */ if( !(prefix = vips_guess_prefix( argv0, "VIPSHOME" )) || !(libdir = vips_guess_libdir( argv0, "VIPSHOME" )) ) return( -1 ); /* Get i18n .mo files from $VIPSHOME/share/locale/. */ vips_snprintf( name, 256, "%s" G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S "locale", prefix ); bindtextdomain( GETTEXT_PACKAGE, name ); bind_textdomain_codeset( GETTEXT_PACKAGE, "UTF-8" ); /* Default various settings from env. */ if( g_getenv( "VIPS_INFO" ) || g_getenv( "IM_INFO" ) ) vips_info_set( TRUE ); if( g_getenv( "VIPS_TRACE" ) ) vips_cache_set_trace( TRUE ); /* Register base vips types. */ (void) vips_image_get_type(); (void) vips_region_get_type(); vips__meta_init_types(); vips__interpolate_init(); im__format_init(); /* Start up operator cache. */ vips__cache_init(); /* Start up packages. */ (void) vips_system_get_type(); vips_arithmetic_operation_init(); vips_conversion_operation_init(); vips_create_operation_init(); vips_foreign_operation_init(); vips_resample_operation_init(); vips_colour_operation_init(); vips_histogram_operation_init(); vips_convolution_operation_init(); vips_freqfilt_operation_init(); vips_morphology_operation_init(); vips_draw_operation_init(); vips_mosaicing_operation_init(); /* Load any vips8 plugins from the vips libdir. Keep going, even if * some plugins fail to load. */ (void) vips_load_plugins( "%s/vips-plugins-%d.%d", libdir, VIPS_MAJOR_VERSION, VIPS_MINOR_VERSION ); /* Load up any vips7 plugins in the vips libdir. We don't error on * failure, it's too annoying to have VIPS refuse to start because of * a broken plugin. */ if( im_load_plugins( "%s/vips-%d.%d", libdir, VIPS_MAJOR_VERSION, VIPS_MINOR_VERSION ) ) { vips_warn( "vips_init", "%s", vips_error_buffer() ); vips_error_clear(); } /* Also load from libdir. This is old and slightly broken behaviour * :-( kept for back compat convenience. */ if( im_load_plugins( "%s", libdir ) ) { vips_warn( "vips_init", "%s", vips_error_buffer() ); vips_error_clear(); } /* Start up the buffer cache. */ vips__buffer_init(); /* Get the run-time compiler going. */ vips_vector_init(); #ifdef HAVE_GSF /* Use this for structured file write. */ gsf_init(); #endif /*HAVE_GSF*/ /* Register vips_shutdown(). This may well not get called and many * platforms don't support it anyway. */ #ifdef HAVE_ATEXIT atexit( vips_shutdown ); #endif /*HAVE_ATEXIT*/ #ifdef DEBUG_LEAK vips__image_pixels_quark = g_quark_from_static_string( "vips-image-pixels" ); #endif /*DEBUG_LEAK*/ done = TRUE; vips__thread_gate_stop( "init: startup" ); return( 0 ); }