Ejemplo n.º 1
0
/**
 * vips_tracked_free:
 * @s: memory to free
 *
 * Only use it to free
 * memory that was previously allocated with vips_tracked_malloc() with a 
 * %NULL first argument.
 *
 * See also: vips_tracked_malloc().
 */
void
vips_tracked_free( void *s )
{
	size_t size;

	/* Keep the size of the alloc in the previous 16 bytes. Ensures
	 * alignment rules are kept.
	 */
	s = (void *) ((char*)s - 16);
	size = *((size_t*)s);

	g_mutex_lock( vips_tracked_mutex );

	if( vips_tracked_allocs <= 0 ) 
		vips_warn( "vips_tracked", 
			"%s", _( "vips_free: too many frees" ) );
	if( vips_tracked_mem < size )
		vips_warn( "vips_tracked", 
			"%s", _( "vips_free: too much free" ) );

	vips_tracked_mem -= size;
	vips_tracked_allocs -= 1;

	g_mutex_unlock( vips_tracked_mutex );

	g_free( s );

	VIPS_GATE_FREE( size ); 
}
Ejemplo n.º 2
0
static void
res_from_exif( VipsImage *im, ExifData *ed )
{
    double xres, yres;
    int unit;

    /* The main image xres/yres are in ifd0. ifd1 has xres/yres of the
     * image thumbnail, if any.
     */
    if( get_entry_double( ed, 0, EXIF_TAG_X_RESOLUTION, &xres ) ||
            get_entry_double( ed, 0, EXIF_TAG_Y_RESOLUTION, &yres ) ||
            get_entry_int( ed, 0, EXIF_TAG_RESOLUTION_UNIT, &unit ) ) {
        vips_warn( "VipsJpeg",
                   "%s", _( "error reading resolution" ) );
        return;
    }

#ifdef DEBUG
    printf( "res_from_exif: seen exif tags "
            "xres = %g, yres = %g, unit = %d\n", xres, yres, unit );
#endif /*DEBUG*/

    switch( unit ) {
    case 2:
        /* In inches.
         */
        xres /= 25.4;
        yres /= 25.4;
        vips_image_set_string( im,
                               VIPS_META_RESOLUTION_UNIT, "in" );
        break;

    case 3:
        /* In cm.
         */
        xres /= 10.0;
        yres /= 10.0;
        vips_image_set_string( im,
                               VIPS_META_RESOLUTION_UNIT, "cm" );
        break;

    default:
        vips_warn( "VipsJpeg",
                   "%s", _( "unknown EXIF resolution unit" ) );
        return;
    }

#ifdef DEBUG
    printf( "res_from_exif: seen exif resolution %g, %g p/mm\n",
            xres, yres );
#endif /*DEBUG*/

    im->Xres = xres;
    im->Yres = yres;
}
Ejemplo n.º 3
0
static int
write_blob( Write *write, const char *field, int app )
{
	unsigned char *data;
	size_t data_length;

	if( vips_image_get_typeof( write->in, field ) ) {
		if( vips_image_get_blob( write->in, field, 
			(void *) &data, &data_length ) )
			return( -1 );

		/* Single jpeg markers can only hold 64kb, large objects must
		 * be split into multiple markers.
		 *
		 * Unfortunately, how this splitting is done depends on the
		 * data type. For example, ICC and XMP have completely 
		 * different ways of doing this.
		 *
		 * For now, just ignore oversize objects and warn.
		 */
		if( data_length > 65530 ) 
			vips_warn( "VipsJpeg", _( "field \"%s\" is too large "
				"for a single JPEG marker, ignoring" ), 
				field );
		else {
#ifdef DEBUG
			printf( "write_blob: attaching %zd bytes of %s\n", 
				data_length, field );
#endif /*DEBUG*/

			jpeg_write_marker( &write->cinfo, app, 
				data, data_length ); } }

	return( 0 );
}
Ejemplo n.º 4
0
/* Call a stop function if a sequence is running in this VipsRegion. 
 */
void
vips__region_stop( VipsRegion *region )
{
	VipsImage *image = region->im;

        if( region->seq && image->stop_fn ) {
		int result;

		VIPS_GATE_START( "vips__region_stop: wait" );

                g_mutex_lock( image->sslock );

		VIPS_GATE_STOP( "vips__region_stop: wait" );

               	result = image->stop_fn( region->seq, 
			image->client1, image->client2 );

                g_mutex_unlock( image->sslock );

		/* stop function can return an error, but we have nothing we
		 * can really do with it, sadly.
		 */
		if( result )
                        vips_warn( "VipsRegion", 
				"stop callback failed for image %s", 
				image->filename );
 
                region->seq = NULL;
        }
}
Ejemplo n.º 5
0
/* Embed any IPCT metadata. 
 */
static int
write_embed_ipct( Write *write, TIFF *tif )
{
	void *data;
	size_t data_length;

	if( !vips_image_get_typeof( write->im, VIPS_META_IPCT_NAME ) )
		return( 0 );
	if( vips_image_get_blob( write->im, VIPS_META_IPCT_NAME, 
		&data, &data_length ) )
		return( -1 );

	/* For no very good reason, libtiff stores IPCT as an array of
	 * long, not byte.
	 */
	if( data_length & 3 ) {
		vips_warn( "vips2tiff", 
			"%s", _( "rounding up IPCT data length" ) );
		data_length /= 4;
		data_length += 1;
	}
	else
		data_length /= 4;

	TIFFSetField( tif, TIFFTAG_RICHTIFFIPTC, data_length, data );

#ifdef DEBUG
	printf( "vips2tiff: attached IPCT from meta\n" );
#endif /*DEBUG*/

	return( 0 );
}
Ejemplo n.º 6
0
static void
vips_thread_profile_save( VipsThreadProfile *profile )
{
	g_mutex_lock( vips__global_lock );

	VIPS_DEBUG_MSG( "vips_thread_profile_save: %s\n", profile->name ); 

	if( !vips__thread_fp ) { 
		vips__thread_fp = 
			vips__file_open_write( "vips-profile.txt", TRUE );
		if( !vips__thread_fp ) {
			g_mutex_unlock( vips__global_lock );
			vips_warn( "VipsGate", 
				"%s", "unable to create profile log" ); 
			return;
		}

		printf( "recording profile in vips-profile.txt\n" );  
	}

	fprintf( vips__thread_fp, "thread: %s (%p)\n", profile->name, profile );
	g_hash_table_foreach( profile->gates, 
		vips_thread_profile_save_cb, vips__thread_fp );
	vips_thread_profile_save_gate( profile->memory, vips__thread_fp ); 

	g_mutex_unlock( vips__global_lock );
}
Ejemplo n.º 7
0
static int 
icc_error( int code, const char *text )
{
	if( code == LCMS_ERRC_WARNING )
		vips_warn( "VipsIcc", "%s", text );
	else
		vips_error( "VipsIcc", "%s", text );

	return( 0 );
}
Ejemplo n.º 8
0
/* This is different, we set the xres/yres from the vips header rather than
 * from the exif tags on the image metadata.
 *
 * This is also called from the jpg reader to fix up bad exif resoltion.
 */
int
vips__set_exif_resolution( ExifData *ed, VipsImage *im )
{
	double xres, yres;
	const char *p;
	int unit;

	VIPS_DEBUG_MSG( "vips__set_exif_resolution: vips res of %g, %g\n",
		im->Xres, im->Yres );

	/* Default to inches, more progs support it.
	 */
	unit = 2;
	if( vips_image_get_typeof( im, VIPS_META_RESOLUTION_UNIT ) &&
		!vips_image_get_string( im, VIPS_META_RESOLUTION_UNIT, &p ) ) {
		if( vips_isprefix( "cm", p ) ) 
			unit = 3;
		else if( vips_isprefix( "none", p ) ) 
			unit = 1;
	}

	switch( unit ) {
	case 1:
		xres = im->Xres;
		yres = im->Yres;
		break;

	case 2:
		xres = im->Xres * 25.4;
		yres = im->Yres * 25.4;
		break;

	case 3:
		xres = im->Xres * 10.0;
		yres = im->Yres * 10.0;
		break;

	default:
		vips_warn( "VipsJpeg", 
			"%s", _( "unknown EXIF resolution unit" ) );
		return( 0 );
	}

	/* Main image xres/yres/unit are in ifd0. ifd1 has the thumbnail
	 * xres/yres/unit.
	 */
	write_tag( ed, 0, EXIF_TAG_X_RESOLUTION, 
		vips_exif_set_double, (void *) &xres );
	write_tag( ed, 0, EXIF_TAG_Y_RESOLUTION, 
		vips_exif_set_double, (void *) &yres );
	write_tag( ed, 0, EXIF_TAG_RESOLUTION_UNIT, 
		vips_exif_set_int, (void *) &unit );

	return( 0 );
}
Ejemplo n.º 9
0
/* 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 );
}
Ejemplo n.º 10
0
static void *
vips_exif_image_field( VipsImage *image, 
	const char *field, GValue *value, void *data )
{
	ExifData *ed = (ExifData *) data;

	const char *string;
	int ifd;
	const char *p;
	ExifTag tag;

	if( !vips_isprefix( "exif-ifd", field ) ) 
		return( NULL );

	/* value must be a string.
	 */
	if( vips_image_get_string( image, field, &string ) ) {
		vips_warn( "VipsJpeg", _( "bad exif meta \"%s\"" ), field );
		return( NULL ); 
	}

	p = field + strlen( "exif-ifd" );
	ifd = atoi( p ); 

	for( ; isdigit( *p ); p++ )
		;
	if( *p != '-' ) {
		vips_warn( "VipsJpeg", _( "bad exif meta \"%s\"" ), field );
		return( NULL ); 
	}

	if( !(tag = exif_tag_from_name( p + 1 )) ) {
		vips_warn( "VipsJpeg", _( "bad exif meta \"%s\"" ), field );
		return( NULL ); 
	}

	write_tag( ed, ifd, tag, vips_exif_set_entry, (void *) string );

	return( NULL ); 
}
Ejemplo n.º 11
0
static int
readjpeg_free( ReadJpeg *jpeg )
{
    int result;

    result = 0;

    if( setjmp( jpeg->eman.jmp ) )
        return( -1 );

    if( jpeg->eman.pub.num_warnings != 0 ) {
        if( jpeg->fail ) {
            vips_error( "VipsJpeg", "%s", vips_error_buffer() );
            result = -1;
        }
        else {
            vips_warn( "VipsJpeg",
                       _( "read gave %ld warnings" ),
                       jpeg->eman.pub.num_warnings );
            vips_warn( NULL, "%s", vips_error_buffer() );
        }

        /* Make the message only appear once.
         */
        jpeg->eman.pub.num_warnings = 0;
    }

    if( jpeg->decompressing ) {
        jpeg_finish_decompress( &jpeg->cinfo );
        jpeg->decompressing = FALSE;
    }

    VIPS_FREEF( fclose, jpeg->eman.fp );
    VIPS_FREE( jpeg->filename );
    jpeg->eman.fp = NULL;
    jpeg_destroy_decompress( &jpeg->cinfo );

    return( result );
}
Ejemplo n.º 12
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 ) ) {
		vips_warn( NULL, "%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 ) {
			vips_warn( NULL, "%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 );
}
Ejemplo n.º 13
0
/* This can be called many times.
 */
static int
readjpeg_free( ReadJpeg *jpeg )
{
	int result;

	result = 0;

	if( jpeg->eman.pub.num_warnings != 0 ) {
		if( jpeg->fail ) {
			vips_error( "VipsJpeg", "%s", vips_error_buffer() );
			result = -1;
		}
		else {
			vips_warn( "VipsJpeg", 
				_( "read gave %ld warnings" ), 
				jpeg->eman.pub.num_warnings );
			vips_warn( NULL, "%s", vips_error_buffer() );
		}

		/* Make the message only appear once.
		 */
		jpeg->eman.pub.num_warnings = 0;
	}

	/* Don't call jpeg_finish_decompress(). It just checks the tail of the
	 * file and who cares about that. All mem is freed in
	 * jpeg_destroy_decompress().
	 */

	VIPS_FREEF( fclose, jpeg->eman.fp );
	VIPS_FREE( jpeg->filename );
	jpeg->eman.fp = NULL;

	/* I don't think this can fail. It's harmless to call many times. 
	 */
	jpeg_destroy_decompress( &jpeg->cinfo );

	return( result );
}
Ejemplo n.º 14
0
/* Read a single item. Syntax is:
 *
 * element : 
 * 	whitespace* item whitespace* [EOF|EOL|separator]
 *
 * item : 
 * 	double |
 * 	"anything" |
 * 	empty
 *
 * the anything in quotes can contain " escaped with \
 *
 * Return the char that caused failure on fail (EOF or \n).
 */
static int
read_double( FILE *fp, const char whitemap[256], const char sepmap[256],
	int lineno, int colno, double *out )
{
	int ch;

	/* The fscanf() may change this ... but all other cases need a zero.
	 */
	*out = 0;

	ch = skip_white( fp, whitemap );
	if( ch == EOF || 
		ch == '\n' ) 
		return( ch );

	if( ch == '"' ) {
		(void) fgetc( fp );
		(void) skip_to_quote( fp );
		ch = fgetc( fp );
	}
	else if( !sepmap[ch] && 
		fscanf( fp, "%lf", out ) != 1 ) {
		/* Only a warning, since (for example) exported spreadsheets
		 * will often have text or date fields.
		 */
		vips_warn( "csv2vips", 
			_( "error parsing number, line %d, column %d" ),
			lineno, colno );

		/* Step over the bad data to the next separator.
		 */
		ch = skip_to_sep( fp, sepmap );
	}

	/* Don't need to check result, we have read a field successfully.
	 */
	ch = skip_white( fp, whitemap );

	/* If it's a separator, we have to step over it. 
	 */
	if( ch != EOF && 
		sepmap[ch] ) 
		(void) fgetc( fp );

	return( 0 );
}
Ejemplo n.º 15
0
/**
 * vips_tracked_malloc:
 * @size: number of bytes to allocate
 *
 * Allocate an area of memory that will be tracked by vips_tracked_get_mem()
 * and friends. 
 *
 * If allocation fails, vips_malloc() returns %NULL and 
 * sets an error message.
 *
 * You must only free the memory returned with vips_tracked_free().
 *
 * See also: vips_tracked_free(), vips_malloc().
 *
 * Returns: a pointer to the allocated memory, or %NULL on error.
 */
void *
vips_tracked_malloc( size_t size )
{
        void *buf;

	vips_tracked_init(); 

	/* Need an extra sizeof(size_t) bytes to track 
	 * size of this block. Ask for an extra 16 to make sure we don't break
	 * alignment rules.
	 */
	size += 16;

        if( !(buf = g_try_malloc( size )) ) {
#ifdef DEBUG
		g_assert( 0 );
#endif /*DEBUG*/

		vips_error( "vips_tracked", 
			_( "out of memory --- size == %dMB" ), 
			(int) (size / (1024.0*1024.0))  );
		vips_warn( "vips_tracked", 
			_( "out of memory --- size == %dMB" ), 
			(int) (size / (1024.0*1024.0))  );

                return( NULL );
	}

	g_mutex_lock( vips_tracked_mutex );

	*((size_t *)buf) = size;
	buf = (void *) ((char *)buf + 16);

	vips_tracked_mem += size;
	if( vips_tracked_mem > vips_tracked_mem_highwater ) 
		vips_tracked_mem_highwater = vips_tracked_mem;
	vips_tracked_allocs += 1;

	g_mutex_unlock( vips_tracked_mutex );

	VIPS_GATE_MALLOC( size ); 

        return( buf );
}
Ejemplo n.º 16
0
static void
vips__thread_profile_init_cb( VipsThreadProfile *profile )
{
	/* We only come here if vips_thread_shutdown() was not called for this
	 * thread. Do our best to clean up.
	 *
	 * GPrivate has stopped working, be careful not to touch that. 
	 *
	 * Don't try to save: we must free all mem before saving and we
	 * probably haven't done that because vips_thread_shutdown() has not
	 * been called. 
	 */
	if( vips__thread_profile ) 
		vips_warn( "VipsGate", 
			"discarding unsaved state for thread %p --- "
			"call vips_thread_shutdown() for this thread",
			profile->thread ); 

	vips_thread_profile_free( profile );
}
Ejemplo n.º 17
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 );
}
Ejemplo n.º 18
0
/* Read a cinfo to a VIPS image. Set invert_pels if the pixel reader needs to
 * do 255-pel.
 */
static int
read_jpeg_header( ReadJpeg *jpeg, VipsImage *out )
{
    struct jpeg_decompress_struct *cinfo = &jpeg->cinfo;

    jpeg_saved_marker_ptr p;
    VipsInterpretation interpretation;
    double xres, yres;

    /* Capture app2 sections here for assembly.
     */
    void *app2_data[MAX_APP2_SECTIONS] = { 0 };
    size_t app2_data_length[MAX_APP2_SECTIONS] = { 0 };
    size_t data_length;
    int i;

    /* Read JPEG header. libjpeg will set out_color_space sanely for us
     * for YUV YCCK etc.
     */
    jpeg_read_header( cinfo, TRUE );
    cinfo->scale_denom = jpeg->shrink;
    cinfo->scale_num = 1;
    jpeg_calc_output_dimensions( cinfo );

    jpeg->invert_pels = FALSE;
    switch( cinfo->out_color_space ) {
    case JCS_GRAYSCALE:
        interpretation = VIPS_INTERPRETATION_B_W;
        break;

    case JCS_CMYK:
        interpretation = VIPS_INTERPRETATION_CMYK;
        /* Photoshop writes CMYK JPEG inverted :-( Maybe this is a
         * way to spot photoshop CMYK JPGs.
         */
        if( cinfo->saw_Adobe_marker )
            jpeg->invert_pels = TRUE;
        break;

    case JCS_RGB:
    default:
        interpretation = VIPS_INTERPRETATION_sRGB;
        break;
    }

    /* Get the jfif resolution. exif may overwrite this later.
     */
    xres = 1.0;
    yres = 1.0;
    if( cinfo->saw_JFIF_marker &&
            cinfo->X_density != 1U &&
            cinfo->Y_density != 1U ) {
#ifdef DEBUG
        printf( "read_jpeg_header: seen jfif _density %d, %d\n",
                cinfo->X_density, cinfo->Y_density );
#endif /*DEBUG*/

        switch( cinfo->density_unit ) {
        case 1:
            /* Pixels per inch.
             */
            xres = cinfo->X_density / 25.4;
            yres = cinfo->Y_density / 25.4;
            break;

        case 2:
            /* Pixels per cm.
             */
            xres = cinfo->X_density / 10.0;
            yres = cinfo->Y_density / 10.0;
            break;

        default:
            vips_warn( "VipsJpeg",
                       "%s", _( "unknown JFIF resolution unit" ) );
            break;
        }

#ifdef DEBUG
        printf( "read_jpeg_header: seen jfif resolution %g, %g p/mm\n",
                xres, yres );
#endif /*DEBUG*/
    }

    /* Set VIPS header.
     */
    vips_image_init_fields( out,
                            cinfo->output_width, cinfo->output_height,
                            cinfo->output_components,
                            VIPS_FORMAT_UCHAR, VIPS_CODING_NONE,
                            interpretation,
                            xres, yres );

    vips_demand_hint( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );

    /* Interlaced jpegs need lots of memory to read, so our caller needs
     * to know.
     */
    (void) vips_image_set_int( out, "jpeg-multiscan",
                               jpeg_has_multiple_scans( cinfo ) );

    /* Look for EXIF and ICC profile.
     */
    for( p = cinfo->marker_list; p; p = p->next ) {
#ifdef DEBUG
        {
            printf( "read_jpeg_header: seen %d bytes of APP%d\n",
            p->data_length,
            p->marker - JPEG_APP0 );

            for( i = 0; i < 10; i++ )
                printf( "\t%d) '%c' (%d)\n",
                i, p->data[i], p->data[i] );
        }
#endif /*DEBUG*/

        switch( p->marker ) {
        case JPEG_APP0 + 1:
            /* Possible EXIF or XMP data.
             */
            if( p->data_length > 4 &&
                    vips_isprefix( "Exif", (char *) p->data ) ) {
                if( parse_exif( out,
                                p->data, p->data_length ) ||
                        attach_blob( out, VIPS_META_EXIF_NAME,
                                     p->data, p->data_length ) )
                    return( -1 );
            }

            if( p->data_length > 4 &&
                    vips_isprefix( "http", (char *) p->data ) &&
                    attach_blob( out, VIPS_META_XMP_NAME,
                                 p->data, p->data_length ) )
                return( -1 );

            break;

        case JPEG_APP0 + 2:
            /* Possible ICC profile.
             */
            if( p->data_length > 14 &&
                    vips_isprefix( "ICC_PROFILE",
                                   (char *) p->data ) ) {
                /* cur_marker numbers from 1, according to
                 * spec.
                 */
                int cur_marker = p->data[12] - 1;

                if( cur_marker >= 0 &&
                        cur_marker < MAX_APP2_SECTIONS ) {
                    app2_data[cur_marker] = p->data + 14;
                    app2_data_length[cur_marker] =
                        p->data_length - 14;
                }
            }
            break;

        case JPEG_APP0 + 13:
            /* Possible IPCT data block.
             */
            if( p->data_length > 5 &&
                    vips_isprefix( "Photo", (char *) p->data ) &&
                    attach_blob( out, VIPS_META_IPCT_NAME,
                                 p->data, p->data_length ) )
                return( -1 );
            break;

        default:
            break;
        }
    }

    /* Assemble ICC sections.
     */
    data_length = 0;
    for( i = 0; i < MAX_APP2_SECTIONS && app2_data[i]; i++ )
        data_length += app2_data_length[i];
    if( data_length ) {
        unsigned char *data;
        int p;

#ifdef DEBUG
        printf( "read_jpeg_header: assembled %zd byte ICC profile\n",
                data_length );
#endif /*DEBUG*/

        if( !(data = vips_malloc( NULL, data_length )) )
            return( -1 );

        p = 0;
        for( i = 0; i < MAX_APP2_SECTIONS && app2_data[i]; i++ ) {
            memcpy( data + p, app2_data[i], app2_data_length[i] );
            p += app2_data_length[i];
        }

        vips_image_set_blob( out, VIPS_META_ICC_NAME,
                             (VipsCallbackFn) vips_free, data, data_length );
    }

    return( 0 );
}
Ejemplo n.º 19
0
int
main( int argc, char **argv )
{
	GOptionContext *context;
	GOptionGroup *main_group;
	GError *error = NULL;
	int i;
	int result;

	if( VIPS_INIT( argv[0] ) )
	        vips_error_exit( "unable to start VIPS" );
	textdomain( GETTEXT_PACKAGE );
	setlocale( LC_ALL, "" );

        context = g_option_context_new( _( "- thumbnail generator" ) );

	main_group = g_option_group_new( NULL, NULL, NULL, NULL, NULL );
	g_option_group_add_entries( main_group, options );
	vips_add_option_entries( main_group ); 
	g_option_group_set_translation_domain( main_group, GETTEXT_PACKAGE );
	g_option_context_set_main_group( context, main_group );

	if( !g_option_context_parse( context, &argc, &argv, &error ) ) {
		if( error ) {
			fprintf( stderr, "%s\n", error->message );
			g_error_free( error );
		}

		vips_error_exit( "try \"%s --help\"", g_get_prgname() );
	}

	g_option_context_free( context );

	if( sscanf( thumbnail_size, "%d x %d", 
		&thumbnail_width, &thumbnail_height ) != 2 ) {
		if( sscanf( thumbnail_size, "%d", &thumbnail_width ) != 1 ) 
			vips_error_exit( "unable to parse size \"%s\" -- "
				"use eg. 128 or 200x300", thumbnail_size );

		thumbnail_height = thumbnail_width;
	}

	if( rotate_image ) {
#ifndef HAVE_EXIF
		vips_warn( "vipsthumbnail", "%s",
			_( "auto-rotate disabled: "
			      "libvips built without exif support" ) );
#endif /*!HAVE_EXIF*/
	}

	result = 0;

	for( i = 1; i < argc; i++ ) {
		/* Hang resources for processing this thumbnail off @process.
		 */
		VipsObject *process = VIPS_OBJECT( vips_image_new() ); 

		if( thumbnail_process( process, argv[i] ) ) {
			fprintf( stderr, "%s: unable to thumbnail %s\n", 
				argv[0], argv[i] );
			fprintf( stderr, "%s", vips_error_buffer() );
			vips_error_clear();

			/* We had a conversion failure: return an error code
			 * when we finally exit.
			 */
			result = -1;
		}

		g_object_unref( process );
	}

	vips_shutdown();

	return( result );
}
Ejemplo n.º 20
0
static VipsImage *
thumbnail_shrink( VipsObject *process, VipsImage *in )
{
	VipsImage **t = (VipsImage **) vips_object_local_array( process, 10 );
	VipsInterpretation interpretation = linear_processing ?
		VIPS_INTERPRETATION_XYZ : VIPS_INTERPRETATION_sRGB; 

	/* TRUE if we've done the import of an ICC transform and still need to
	 * export.
	 */
	gboolean have_imported;

	/* TRUE if we've premultiplied and need to unpremultiply.
	 */
	gboolean have_premultiplied;
	VipsBandFormat unpremultiplied_format;

	/* Sniff the incoming image and try to guess what the alpha max is.
	 */
	double max_alpha;

	double shrink; 

	/* 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];
	}

	/* Try to guess what the maximum alpha might be.
	 */
	max_alpha = 255;
	if( in->BandFmt == VIPS_FORMAT_USHORT )
		max_alpha = 65535;

	/* In linear mode, we import right at the start. 
	 *
	 * We also have to import the whole image if it's CMYK, since
	 * vips_colourspace() (see below) doesn't know about CMYK.
	 *
	 * 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. 
	 */
	have_imported = FALSE;
	if( (linear_processing ||
		in->Type == VIPS_INTERPRETATION_CMYK) &&
		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];

		have_imported = TRUE;
	}

	/* 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];

	/* If there's an alpha, we have to premultiply before shrinking. See
	 * https://github.com/jcupitt/libvips/issues/291
	 */
	have_premultiplied = FALSE;
	if( in->Bands == 2 ||
		(in->Bands == 4 && in->Type != VIPS_INTERPRETATION_CMYK) ||
		in->Bands == 5 ) {
		vips_info( "vipsthumbnail", "premultiplying alpha" ); 
		if( vips_premultiply( in, &t[3], 
			"max_alpha", max_alpha,
			NULL ) ) 
			return( NULL );
		have_premultiplied = TRUE;

		/* vips_premultiply() makes a float image. When we
		 * vips_unpremultiply() below, we need to cast back to the
		 * pre-premultiply format.
		 */
		unpremultiplied_format = in->BandFmt;
		in = t[3];
	}

	shrink = calculate_shrink( in );

	if( vips_resize( in, &t[4], 1.0 / shrink, NULL ) ) 
		return( NULL );
	in = t[4];

	if( have_premultiplied ) {
		vips_info( "vipsthumbnail", "unpremultiplying alpha" ); 
		if( vips_unpremultiply( in, &t[5], 
			"max_alpha", max_alpha,
			NULL ) || 
			vips_cast( t[5], &t[6], unpremultiplied_format, NULL ) )
			return( NULL );
		in = t[6];
	}

	/* Colour management.
	 *
	 * If we've already imported, just export. Otherwise, we're in 
	 * device space and we need a combined import/export to transform to 
	 * the target space.
	 */
	if( have_imported ) { 
		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[7], 
				VIPS_INTERPRETATION_sRGB, NULL ) ) 
				return( NULL ); 
			in = t[7];
		}
	}
	else if( export_profile &&
		(vips_image_get_typeof( in, VIPS_META_ICC_NAME ) || 
		 import_profile) ) {
		VipsImage *out;

		vips_info( "vipsthumbnail", 
			"exporting with profile %s", export_profile );

		/* We first try with the embedded profile, if any, then if
		 * that fails try again with the supplied fallback profile.
		 */
		out = NULL; 
		if( vips_image_get_typeof( in, VIPS_META_ICC_NAME ) ) {
			vips_info( "vipsthumbnail", 
				"importing with embedded profile" );

			if( vips_icc_transform( in, &t[7], export_profile,
				"embedded", TRUE,
				NULL ) ) {
				vips_warn( "vipsthumbnail", 
					_( "unable to import with "
						"embedded profile: %s" ),
					vips_error_buffer() );

				vips_error_clear();
			}
			else
				out = t[7];
		}

		if( !out &&
			import_profile ) { 
			vips_info( "vipsthumbnail", 
				"importing with fallback profile" );

			if( vips_icc_transform( in, &t[7], export_profile,
				"input_profile", import_profile,
				"embedded", FALSE,
				NULL ) )  
				return( NULL );

			out = t[7];
		}

		/* If the embedded profile failed and there's no fallback or
		 * the fallback failed, out will still be NULL.
		 */
		if( out )
			in = out;
	}

	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 );
}
Ejemplo n.º 21
0
/* Make and init a Write.
 */
static Write *
write_new( VipsImage *im, const char *filename,
	VipsForeignTiffCompression compression, int Q, 
		VipsForeignTiffPredictor predictor,
	char *profile,
	gboolean tile, int tile_width, int tile_height,
	gboolean pyramid,
	gboolean squash,
	gboolean miniswhite,
	VipsForeignTiffResunit resunit, double xres, double yres,
	gboolean bigtiff,
	gboolean rgbjpeg,
	gboolean properties,
	gboolean strip )
{
	Write *write;

	if( !(write = VIPS_NEW( im, Write )) )
		return( NULL );
	write->im = im;
	write->filename = vips_strdup( VIPS_OBJECT( im ), filename );
	write->layer = NULL;
	write->tbuf = NULL;
	write->compression = get_compression( compression );
	write->jpqual = Q;
	write->predictor = predictor;
	write->tile = tile;
	write->tilew = tile_width;
	write->tileh = tile_height;
	write->pyramid = pyramid;
	write->onebit = squash;
	write->miniswhite = miniswhite;
	write->icc_profile = vips_strdup( NULL, profile );
	write->bigtiff = bigtiff;
	write->rgbjpeg = rgbjpeg;
	write->properties = properties;
	write->strip = strip;

	write->resunit = get_resunit( resunit );
	write->xres = xres;
	write->yres = yres;

	/* In strip mode we use tileh to set rowsperstrip, and that does not
	 * have the multiple-of-16 restriction.
	 */
	if( tile ) { 
		if( (write->tilew & 0xf) != 0 || 
			(write->tileh & 0xf) != 0 ) {
			vips_error( "vips2tiff", 
				"%s", _( "tile size not a multiple of 16" ) );
			return( NULL );
		}
	}

	/* We can only pyramid LABQ and non-complex images. 
	 */
	if( write->pyramid ) {
		if( im->Coding == VIPS_CODING_NONE && 
			vips_band_format_iscomplex( im->BandFmt ) ) {
			vips_error( "vips2tiff", 
				"%s", _( "can only pyramid LABQ and "
				"non-complex images" ) );
			return( NULL );
		}
	}

	/* Only 1-bit-ize 8 bit mono images.
	 */
	if( write->onebit &&
		(im->Coding != VIPS_CODING_NONE || 
			im->BandFmt != VIPS_FORMAT_UCHAR ||
			im->Bands != 1) ) {
		vips_warn( "vips2tiff", 
			"%s", _( "can only squash 1 band uchar images -- "
				"disabling squash" ) );
		write->onebit = 0;
	}

	if( write->onebit && 
		write->compression == COMPRESSION_JPEG ) {
		vips_warn( "vips2tiff", 
			"%s", _( "can't have 1-bit JPEG -- disabling JPEG" ) );
		write->compression = COMPRESSION_NONE;
	}
 
	/* We can only MINISWHITE non-complex images of 1 or 2 bands.
	 */
	if( write->miniswhite &&
		(im->Coding != VIPS_CODING_NONE || 
			vips_band_format_iscomplex( im->BandFmt ) ||
			im->Bands > 2) ) {
		vips_warn( "vips2tiff", 
			"%s", _( "can only save non-complex greyscale images "
				"as miniswhite -- disabling miniswhite" ) );
		write->miniswhite = FALSE;
	}

	/* Sizeof a line of bytes in the TIFF tile.
	 */
	if( im->Coding == VIPS_CODING_LABQ )
		write->tls = write->tilew * 3;
	else if( write->onebit )
		write->tls = VIPS_ROUND_UP( write->tilew, 8 ) / 8;
	else
		write->tls = VIPS_IMAGE_SIZEOF_PEL( im ) * write->tilew;

	/* Build the pyramid framework.
	 */
	write->layer = pyramid_new( write, NULL, im->Xsize, im->Ysize );

	/* Fill all the layers.
	 */
	if( pyramid_fill( write ) ) {
		write_free( write );
		return( NULL );
	}

	if( tile ) 
		write->tbuf = vips_malloc( NULL, 
			TIFFTileSize( write->layer->tif ) );
	else
		write->tbuf = vips_malloc( NULL, 
			TIFFScanlineSize( write->layer->tif ) );
	if( !write->tbuf ) {
		write_free( write );
		return( NULL );
	}

	return( write );
}
Ejemplo n.º 22
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 );
}
Ejemplo n.º 23
0
void *
vips__mmap( int fd, int writeable, size_t length, gint64 offset )
{
	void *baseaddr;

#ifdef DEBUG
	printf( "vips__mmap: length = 0x%zx, offset = 0x%lx\n", 
		length, offset );
#endif /*DEBUG*/

#ifdef OS_WIN32
{
	HANDLE hFile = (HANDLE) _get_osfhandle( fd );

	DWORD flProtect;
	DWORD dwDesiredAccess;

        HANDLE hMMFile;

	ULARGE_INTEGER quad;
	DWORD dwFileOffsetHigh;
	DWORD dwFileOffsetLow;

	if( writeable ) {
		flProtect = PAGE_READWRITE;
		dwDesiredAccess = FILE_MAP_WRITE;
	}
	else {
		flProtect = PAGE_READONLY;
		dwDesiredAccess = FILE_MAP_READ;
	}

	quad.QuadPart = offset;
	dwFileOffsetLow = quad.LowPart;
	dwFileOffsetHigh = quad.HighPart;

        if( !(hMMFile = CreateFileMapping( hFile,
		NULL, flProtect, 0, 0, NULL )) ) {
                vips_error_system( GetLastError(), "vips_mapfile", 
			"%s", _( "unable to CreateFileMapping" ) );
		printf( "CreateFileMapping failed: %s\n", vips_error_buffer() );
                return( NULL );
        }

        if( !(baseaddr = (char *)MapViewOfFile( hMMFile, dwDesiredAccess, 
		dwFileOffsetHigh, dwFileOffsetLow, length )) ) {
                vips_error_system( GetLastError(), "vips_mapfile",
			"%s", _( "unable to MapViewOfFile" ) );
		printf( "MapViewOfFile failed: %s\n", vips_error_buffer() );
		CloseHandle( hMMFile );
                return( NULL );
        }

	/* Can close mapping now ... view stays until UnmapViewOfFile().

		FIXME ... is this a performance problem?

	 */
	CloseHandle( hMMFile );
}
#else /*!OS_WIN32*/
{
	int prot;
	int flags;

	if( writeable ) 
		prot = PROT_WRITE;
	else 
		prot = PROT_READ;

	flags = MAP_SHARED;

	/* OS X caches mmapped files very aggressively if this flags is not
	 * set. Scanning a large file without this flag will cause every other
	 * process to get swapped out and kill performance.
	 */
#ifdef MAP_NOCACHE
	flags |= MAP_NOCACHE;
#endif /*MAP_NOCACHE*/

	/* Casting gint64 to off_t should be safe, even on *nixes without
	 * LARGEFILE.
	 */

	baseaddr = mmap( 0, length, prot, MAP_SHARED, fd, (off_t) offset );
	if( baseaddr == MAP_FAILED ) { 
		vips_error_system( errno, "vips_mapfile", 
			"%s", _( "unable to mmap" ) );
		vips_warn( "vips_mapfile", _( "map failed (%s), "
			"running very low on system resources, "
			"expect a crash soon" ), strerror( errno ) );
		return( NULL ); 
	}
}
#endif /*OS_WIN32*/

	return( baseaddr );
}
Ejemplo n.º 24
0
static int
read_header( Read *read, VipsImage *out )
{
	vips_image_init_fields( out,
		read->width, read->height,
		read->config.input.has_alpha ? 4 : 3,
		VIPS_FORMAT_UCHAR, VIPS_CODING_NONE,
		VIPS_INTERPRETATION_sRGB,
		1.0, 1.0 );

	vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );

#ifdef HAVE_LIBWEBPMUX
{
	WebPData bitstream;
	WebPMux *mux;
	int i;

	/* We have to parse the whole file again to get the metadata out.
	 *
	 * Don't make parse failure an error. We don't want to refuse to read
	 * any pixels because of some malformed metadata.
	 */
	bitstream.bytes = read->data;
	bitstream.size = read->length;
	if( !(mux = WebPMuxCreate( &bitstream, 0 )) ) {
		vips_warn( "webp", "%s", _( "unable to read image metadata" ) ); 
		return( 0 ); 
	}

	for( i = 0; i < vips__n_webp_names; i++ ) { 
		const char *vips = vips__webp_names[i].vips;
		const char *webp = vips__webp_names[i].webp;

		WebPData data;

		if( WebPMuxGetChunk( mux, webp, &data ) == WEBP_MUX_OK ) { 
			void *blob;

			if( !(blob = vips_malloc( NULL, data.size )) ) {
				WebPMuxDelete( mux ); 
				return( -1 ); 
			}

			memcpy( blob, data.bytes, data.size );
			vips_image_set_blob( out, vips, 
				(VipsCallbackFn) vips_free, blob, data.size );
		}
	}

	WebPMuxDelete( mux ); 

	/* We may have read some exif ... parse into the header.
	 */
	if( vips__exif_parse( out ) )
		return( -1 ); 
}
#endif /*HAVE_LIBWEBPMUX*/

	return( 0 );
}
Ejemplo n.º 25
0
/* Write a VIPS image to a JPEG compress struct.
 */
static int
write_vips( Write *write, int qfac, const char *profile, 
	gboolean optimize_coding, gboolean progressive, gboolean strip, 
	gboolean no_subsample, gboolean trellis_quant,
	gboolean overshoot_deringing, gboolean optimize_scans, int quant_table )
{
	VipsImage *in;
	J_COLOR_SPACE space;

	/* The image we'll be writing ... can change, see CMYK.
	 */
	in = write->in;

	/* Should have been converted for save.
	 */
        g_assert( in->BandFmt == VIPS_FORMAT_UCHAR );
	g_assert( in->Coding == VIPS_CODING_NONE );
        g_assert( in->Bands == 1 || 
		in->Bands == 3 || 
		in->Bands == 4 );

        /* Check input image.
         */
	if( vips_image_pio_input( in ) )
		return( -1 );

	/* Set compression parameters.
	 */
        write->cinfo.image_width = in->Xsize;
        write->cinfo.image_height = in->Ysize;
	write->cinfo.input_components = in->Bands;
	if( in->Bands == 4 && 
		in->Type == VIPS_INTERPRETATION_CMYK ) {
		space = JCS_CMYK;
		/* IJG always sets an Adobe marker, so we should invert CMYK.
		 */
		if( vips_invert( in, &write->inverted, NULL ) ) 
			return( -1 );
		in = write->inverted;
	}
	else if( in->Bands == 3 )
		space = JCS_RGB;
	else if( in->Bands == 1 )
		space = JCS_GRAYSCALE;
	else 
		/* Use luminance compression for all channels.
		 */
		space = JCS_UNKNOWN;
	write->cinfo.in_color_space = space; 

	/* Build VIPS output stuff now we know the image we'll be writing.
	 */
	if( !(write->row_pointer = VIPS_ARRAY( NULL, in->Ysize, JSAMPROW )) )
		return( -1 );

#ifdef HAVE_JPEG_EXT_PARAMS
	/* Reset compression profile to libjpeg defaults
	 */
	if( jpeg_c_int_param_supported( &write->cinfo, JINT_COMPRESS_PROFILE ) )
		jpeg_c_set_int_param( &write->cinfo, 
			JINT_COMPRESS_PROFILE, JCP_FASTEST );
#endif

	/* Reset to default.
	 */
        jpeg_set_defaults( &write->cinfo );

 	/* Compute optimal Huffman coding tables.
	 */
	write->cinfo.optimize_coding = optimize_coding;

#ifdef HAVE_JPEG_EXT_PARAMS
	/* Apply trellis quantisation to each 8x8 block. Implies 
	 * "optimize_coding".
	 */
	if( trellis_quant ) {
		if( jpeg_c_bool_param_supported( &write->cinfo, 
			JBOOLEAN_TRELLIS_QUANT ) ) {
			jpeg_c_set_bool_param( &write->cinfo,
				JBOOLEAN_TRELLIS_QUANT, TRUE );
			write->cinfo.optimize_coding = TRUE;
		}
		else 
			vips_warn( "vips2jpeg", 
				"%s", _( "trellis_quant unsupported" ) );
	}

	/* Apply overshooting to samples with extreme values e.g. 0 & 255 
	 * for 8-bit.
	 */
	if( overshoot_deringing ) {
		if( jpeg_c_bool_param_supported( &write->cinfo, 
			JBOOLEAN_OVERSHOOT_DERINGING ) ) 
			jpeg_c_set_bool_param( &write->cinfo,
				JBOOLEAN_OVERSHOOT_DERINGING, TRUE );
		else 
			vips_warn( "vips2jpeg", 
				"%s", _( "overshoot_deringing unsupported" ) );
	}
	/* Split the spectrum of DCT coefficients into separate scans.
	 * Requires progressive output. Must be set before 
	 * jpeg_simple_progression.
	 */
	if( optimize_scans ) {
		if( progressive ) {
			if( jpeg_c_bool_param_supported( &write->cinfo, 
				JBOOLEAN_OPTIMIZE_SCANS ) ) 
				jpeg_c_set_bool_param( &write->cinfo, 
					JBOOLEAN_OPTIMIZE_SCANS, TRUE );
			else 
				vips_warn( "vips2jpeg", 
					"%s", _( "Ignoring optimize_scans" ) );
		}
		else 
			vips_warn( "vips2jpeg", "%s",
				_( "Ignoring optimize_scans for baseline" ) );
	}

	/* Use predefined quantization table.
	 */
	if( quant_table > 0 ) {
		if( jpeg_c_int_param_supported( &write->cinfo,
			JINT_BASE_QUANT_TBL_IDX ) )
			jpeg_c_set_int_param( &write->cinfo,
				JINT_BASE_QUANT_TBL_IDX, quant_table );
		else
			vips_warn( "vips2jpeg",
				"%s", _( "Setting quant_table unsupported" ) );
	}
#else
	/* Using jpeglib.h without extension parameters, warn of ignored 
	 * options.
	 */
	if( trellis_quant ) 
		vips_warn( "vips2jpeg", "%s", _( "Ignoring trellis_quant" ) );
	if( overshoot_deringing ) 
		vips_warn( "vips2jpeg", 
			"%s", _( "Ignoring overshoot_deringing" ) );
	if( optimize_scans ) 
		vips_warn( "vips2jpeg", "%s", _( "Ignoring optimize_scans" ) );
	if( quant_table > 0 )
		vips_warn( "vips2jpeg", "%s", _( "Ignoring quant_table" ) );
#endif

	/* Set compression quality. Must be called after setting params above.
	 */
        jpeg_set_quality( &write->cinfo, qfac, TRUE );

	/* Enable progressive write.
	 */
	if( progressive ) 
		jpeg_simple_progression( &write->cinfo ); 

	/* Turn off chroma subsampling. Follow IM and do it automatically for
	 * high Q. 
	 */
	if( no_subsample ||
		qfac > 90 ) { 
		int i;

		for( i = 0; i < in->Bands; i++ ) { 
			write->cinfo.comp_info[i].h_samp_factor = 1;
			write->cinfo.comp_info[i].v_samp_factor = 1;
		}
	}

	/* Don't write the APP0 JFIF headers if we are stripping.
	 */
	if( strip ) 
		write->cinfo.write_JFIF_header = FALSE;

	/* Build compress tables.
	 */
	jpeg_start_compress( &write->cinfo, TRUE );

	/* Write any APP markers we need.
	 */
	if( !strip ) { 
		if( write_exif( write ) ||
			write_blob( write, 
				VIPS_META_XMP_NAME, JPEG_APP0 + 1 ) ||
			write_blob( write, 
				VIPS_META_IPCT_NAME, JPEG_APP0 + 13 ) )
			return( -1 );

		/* A profile supplied as an argument overrides an embedded 
		 * profile. "none" means don't attach a profile.
		 */
		if( profile && 
			strcmp( profile, "none" ) != 0 &&
			write_profile_file( write, profile ) )
			return( -1 );
		if( !profile && 
			vips_image_get_typeof( in, VIPS_META_ICC_NAME ) && 
			write_profile_meta( write ) )
			return( -1 );
	}

	/* Write data. Note that the write function grabs the longjmp()!
	 */
	if( vips_sink_disc( in, write_jpeg_block, write ) )
		return( -1 );

	/* We have to reinstate the setjmp() before we jpeg_finish_compress().
	 */
	if( setjmp( write->eman.jmp ) ) 
		return( -1 );

	jpeg_finish_compress( &write->cinfo );

	return( 0 );
}