diff --git a/TODO b/TODO index 707fb5f9..6d18b34c 100644 --- a/TODO +++ b/TODO @@ -1,25 +1,24 @@ -- need vips load/save class, so we can detect vips files for native read / - write +- do jpegbuffer load and save - jpeg load needs to set suffs + need a jpegsave base class, with subclasses for save to file and save to + buffer - get image.c using the new system for vips_image_new_from_file() - - CLI stuff image->new_from_string() needs to use new system too, chcek this - - savers need it too ... delayed save system and also - image->output_to_arg() + same for jpegload make compat wrappers for old im_jpeg2vips() and im_vips2jpeg() - move format/* to deprecated + make sure we are using the operation cache for jpegload + + have something to print the cache before we flush it? try tiff load + move format/* to deprecated + + -- return missing just after read_xmp() in master? diff --git a/libvips/deprecated/dispatch_types.c b/libvips/deprecated/dispatch_types.c index 1178d9d3..53f7a23f 100644 --- a/libvips/deprecated/dispatch_types.c +++ b/libvips/deprecated/dispatch_types.c @@ -876,6 +876,10 @@ input_interpolate_init( im_object *obj, char *str ) interpolate_class = vips_class_find( "VipsInterpolate", "interpolate" ); if( !(object = vips_object_new_from_string( interpolate_class, str )) ) return( -1 ); + if( vips_object_build( object ) ) { + g_object_unref( object ); + return( -1 ); + } *obj = object; return( 0 ); diff --git a/libvips/file/file.c b/libvips/file/file.c index f6816e4e..ada5fb45 100644 --- a/libvips/file/file.c +++ b/libvips/file/file.c @@ -234,7 +234,7 @@ vips_file_print_class( VipsObjectClass *object_class, VipsBuf *buf ) VIPS_OBJECT_CLASS( vips_file_parent_class )-> print_class( object_class, buf ); - vips_buf_appends( buf, ", " ); + vips_buf_appends( buf, " " ); if( class->suffs ) { vips_buf_appends( buf, "(" ); @@ -243,7 +243,7 @@ vips_file_print_class( VipsObjectClass *object_class, VipsBuf *buf ) if( p[1] ) vips_buf_appends( buf, ", " ); } - vips_buf_appends( buf, ") " ); + vips_buf_appends( buf, "), " ); } vips_buf_appendf( buf, "priority=%d", class->priority ); @@ -364,6 +364,77 @@ vips_file_load_print_class( VipsObjectClass *object_class, VipsBuf *buf ) vips_buf_appends( buf, ", load" ); } +/* Can this VipsFile open this file? + */ +static void * +vips_file_load_new_from_file_sub( VipsFileLoadClass *load_class, + const char *filename ) +{ + VipsFileClass *class = VIPS_FILE_CLASS( load_class ); + + if( load_class->is_a ) { + if( load_class->is_a( filename ) ) + return( load_class ); + } + else if( vips_filename_suffix_match( filename, class->suffs ) ) + return( load_class ); + + return( NULL ); +} + +/** + * vips_file_find_load: + * @filename: file to find a file for + * + * Searches for an operation you could use to load a file. + * + * See also: vips_file_read(). + * + * Returns: the nmae of an operation on success, %NULL on error + */ +const char * +vips_file_find_load( const char *filename ) +{ + VipsFileLoadClass *load_class; + + if( !vips_existsf( "%s", filename ) ) { + vips_error( "VipsFileLoad", + _( "file \"%s\" not found" ), filename ); + return( NULL ); + } + + if( !(load_class = (VipsFileLoadClass *) vips_file_map( + "VipsFileLoad", + (VipsSListMap2Fn) vips_file_load_new_from_file_sub, + (void *) filename, NULL )) ) { + vips_error( "VipsFileLoad", + _( "file \"%s\" not a known file" ), filename ); + return( NULL ); + } + + return( G_OBJECT_CLASS_NAME( load_class ) ); +} + +static VipsObject * +vips_file_load_new_from_string( const char *string ) +{ + const char *file_op; + GType type; + VipsFileLoad *load; + + if( !(file_op = vips_file_find_load( string )) ) + return( NULL ); + type = g_type_from_name( file_op ); + g_assert( type ); + + load = VIPS_FILE_LOAD( g_object_new( type, NULL ) ); + g_object_set( load, + "filename", string, + NULL ); + + return( VIPS_OBJECT( load ) ); +} + static size_t vips_get_disc_threshold( void ) { @@ -414,7 +485,7 @@ vips_file_load_start_cb( VipsImage *out, void *a, void *dummy ) */ if( load->disc && disc_threshold && - (load->flags & VIPS_FORMAT_PARTIAL) && + (load->flags & VIPS_FILE_PARTIAL) && image_size > disc_threshold ) if( !(load->real = vips_image_new_disc_temp( "%s.v" )) ) return( NULL ); @@ -476,24 +547,34 @@ vips_file_load_build( VipsObject *object ) build( object ) ) return( -1 ); - /* Read header fields to init the return image. THINSTRIP since this is - * probably a disc file. We can't tell yet whether we will be opening - * to memory, sadly, so we can't suggest ANY. + /* Read the header into @out. */ if( class->header && class->header( load ) ) return( -1 ); - vips_demand_hint( load->out, VIPS_DEMAND_STYLE_THINSTRIP, NULL ); - /* Then 'start' creates the real image and 'gen' fetches pixels for - * 'out' from real on demand. + /* If there's no ->load() method then the header read has done + * everything. Otherwise, it's just set fields and we now must + * convert pixels on demand. */ - if( vips_image_generate( load->out, - vips_file_load_start_cb, - vips_file_load_generate_cb, - vips_stop_one, - load, NULL ) ) - return( -1 ); + if( class->load ) { + /* THINSTRIP since this is probably a disc file. + * We can't tell yet whether we will be opening + * to memory, sadly, so we can't suggest ANY. + */ + vips_demand_hint( load->out, + VIPS_DEMAND_STYLE_THINSTRIP, NULL ); + + /* Then 'start' creates the real image and 'gen' fetches + * pixels for @out from @real on demand. + */ + if( vips_image_generate( load->out, + vips_file_load_start_cb, + vips_file_load_generate_cb, + vips_stop_one, + load, NULL ) ) + return( -1 ); + } return( 0 ); } @@ -508,10 +589,11 @@ vips_file_load_class_init( VipsFileLoadClass *class ) gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; + object_class->build = vips_file_load_build; + object_class->print_class = vips_file_load_print_class; + object_class->new_from_string = vips_file_load_new_from_string; object_class->nickname = "fileload"; object_class->description = _( "file loaders" ); - object_class->print_class = vips_file_load_print_class; - object_class->build = vips_file_load_build; VIPS_ARG_IMAGE( class, "out", 2, _( "Output" ), @@ -541,57 +623,6 @@ vips_file_load_init( VipsFileLoad *load ) load->disc = TRUE; } -/* Can this file open this file? - */ -static void * -vips_file_load_new_from_file_sub( VipsFileLoadClass *load_class, - const char *filename ) -{ - VipsFileClass *class = VIPS_FILE_CLASS( load_class ); - - if( load_class->is_a ) { - if( load_class->is_a( filename ) ) - return( load_class ); - } - else if( vips_filename_suffix_match( filename, class->suffs ) ) - return( load_class ); - - return( NULL ); -} - -/** - * vips_file_find_load: - * @filename: file to find a file for - * - * Searches for an operation you could use to load a file. - * - * See also: vips_file_read(). - * - * Returns: the nmae of an operation on success, %NULL on error - */ -const char * -vips_file_find_load( const char *filename ) -{ - VipsFileLoadClass *load_class; - - if( !vips_existsf( "%s", filename ) ) { - vips_error( "VipsFileLoad", - _( "file \"%s\" not found" ), filename ); - return( NULL ); - } - - if( !(load_class = (VipsFileLoadClass *) vips_file_map( - "VipsFileLoad", - (VipsSListMap2Fn) vips_file_load_new_from_file_sub, - (void *) filename, NULL )) ) { - vips_error( "VipsFileLoad", - _( "file \"%s\" not a known file" ), filename ); - return( NULL ); - } - - return( G_OBJECT_CLASS_NAME( load_class ) ); -} - /* Abstract base class for image savers. */ @@ -619,6 +650,69 @@ vips_file_save_print_class( VipsObjectClass *object_class, VipsBuf *buf ) VIPS_ENUM_NICK( VIPS_TYPE_SAVEABLE, class->saveable ) ); } +/* Can we write this filename with this file? + */ +static void * +vips_file_save_new_from_filename_sub( VipsFileSaveClass *save_class, + const char *filename ) +{ + VipsFileClass *class = VIPS_FILE_CLASS( save_class ); + + if( vips_filename_suffix_match( filename, class->suffs ) ) + return( save_class ); + + return( NULL ); +} + +/** + * vips_file_find_save: + * @filename: name to find a file for + * + * Searches for an operation you could use to save a file. + * + * See also: vips_file_write(). + * + * Returns: the name of an operation on success, %NULL on error + */ +const char * +vips_file_find_save( const char *filename ) +{ + VipsFileSaveClass *save_class; + + if( !(save_class = (VipsFileSaveClass *) vips_file_map( + "VipsFileSave", + (VipsSListMap2Fn) vips_file_save_new_from_filename_sub, + (void *) filename, NULL )) ) { + vips_error( "VipsFileSave", + _( "\"%s\" is not a supported image file." ), + filename ); + + return( NULL ); + } + + return( G_OBJECT_CLASS_NAME( save_class ) ); +} + +static VipsObject * +vips_file_save_new_from_string( const char *string ) +{ + const char *file_op; + GType type; + VipsFileSave *save; + + if( !(file_op = vips_file_find_save( string )) ) + return( NULL ); + type = g_type_from_name( file_op ); + g_assert( type ); + + save = VIPS_FILE_SAVE( g_object_new( type, NULL ) ); + g_object_set( save, + "filename", string, + NULL ); + + return( VIPS_OBJECT( save ) ); +} + /* Generate the saveable image. */ static int @@ -843,10 +937,11 @@ vips_file_save_class_init( VipsFileSaveClass *class ) gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; + object_class->build = vips_file_save_build; + object_class->print_class = vips_file_save_print_class; + object_class->new_from_string = vips_file_save_new_from_string; object_class->nickname = "filesave"; object_class->description = _( "file savers" ); - object_class->print_class = vips_file_save_print_class; - object_class->build = vips_file_save_build; VIPS_ARG_IMAGE( class, "in", 0, _( "Input" ), @@ -860,49 +955,6 @@ vips_file_save_init( VipsFileSave *object ) { } -/* Can we write this filename with this file? - */ -static void * -vips_file_save_new_from_filename_sub( VipsFileSaveClass *save_class, - const char *filename ) -{ - VipsFileClass *class = VIPS_FILE_CLASS( save_class ); - - if( vips_filename_suffix_match( filename, class->suffs ) ) - return( save_class ); - - return( NULL ); -} - -/** - * vips_file_find_save: - * @filename: name to find a file for - * - * Searches for an operation you could use to save a file. - * - * See also: vips_file_write(). - * - * Returns: the name of an operation on success, %NULL on error - */ -const char * -vips_file_find_save( const char *filename ) -{ - VipsFileSaveClass *save_class; - - if( !(save_class = (VipsFileSaveClass *) vips_file_map( - "VipsFileSave", - (VipsSListMap2Fn) vips_file_save_new_from_filename_sub, - (void *) filename, NULL )) ) { - vips_error( "VipsFileSave", - _( "\"%s\" is not a supported image file." ), - filename ); - - return( NULL ); - } - - return( G_OBJECT_CLASS_NAME( save_class ) ); -} - /** * vips_file_read: * @filename: file to load diff --git a/libvips/file/jpegload.c b/libvips/file/jpegload.c index a74d6d8d..d1d386a3 100644 --- a/libvips/file/jpegload.c +++ b/libvips/file/jpegload.c @@ -901,11 +901,14 @@ vips_file_load_jpeg_load( VipsFileLoad *load ) return( result ); } +static const char *jpeg_suffs[] = { ".jpg", ".jpeg", ".jpe", NULL }; + static void vips_file_load_jpeg_class_init( VipsFileLoadJpegClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsFileClass *file_class = (VipsFileClass *) class; VipsFileLoadClass *load_class = (VipsFileLoadClass *) class; gobject_class->set_property = vips_object_set_property; @@ -915,6 +918,8 @@ vips_file_load_jpeg_class_init( VipsFileLoadJpegClass *class ) object_class->description = _( "load jpeg from file" ); object_class->build = vips_file_load_jpeg_build; + file_class->suffs = jpeg_suffs; + load_class->is_a = vips_file_load_jpeg_is_a; load_class->header = vips_file_load_jpeg_header; load_class->load = vips_file_load_jpeg_load; @@ -932,7 +937,6 @@ vips_file_load_jpeg_class_init( VipsFileLoadJpegClass *class ) VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET( VipsFileLoadJpeg, fail ), FALSE ); - } static void diff --git a/libvips/file/jpegsave.c b/libvips/file/jpegsave.c index 639bf888..642b7b37 100644 --- a/libvips/file/jpegsave.c +++ b/libvips/file/jpegsave.c @@ -852,7 +852,6 @@ vips_file_save_jpeg_class_init( VipsFileSaveJpegClass *class ) VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET( VipsFileSaveJpeg, profile ), NULL ); - } static void diff --git a/libvips/file/vipsload.c b/libvips/file/vipsload.c index 60ff1a77..fbff46a1 100644 --- a/libvips/file/vipsload.c +++ b/libvips/file/vipsload.c @@ -42,38 +42,31 @@ #include #include +#include typedef VipsFileLoad VipsFileLoadVips; typedef VipsFileLoadClass VipsFileLoadVipsClass; -G_DEFINE_TYPE( VipsFileLoadVips, vips_file_load_vips, VIPS_TYPE_FILE_SAVE ); +G_DEFINE_TYPE( VipsFileLoadVips, vips_file_load_vips, VIPS_TYPE_FILE_LOAD ); -static int -vips_file_load_vips_build( VipsObject *object ) +static gboolean +vips_file_load_vips_is_a( const char *filename ) { - if( VIPS_OBJECT_CLASS( vips_file_load_vips_parent_class )-> - build( object ) ) - return( -1 ); - - return( 0 ); + return( vips__file_magic( filename ) ); } static int -vips_file_load_vips_is_a( const char *filename ) +vips_file_load_vips_get_flags( VipsFileLoad *load ) { - unsigned char buf[4]; + VipsFile *file = VIPS_FILE( load ); - if( vips__get_bytes( filename, buf, 4 ) ) { - if( buf[0] == 0x08 && buf[1] == 0xf2 && - buf[2] == 0xa6 && buf[3] == 0xb6 ) - /* SPARC-order VIPS image. - */ - return( 1 ); - else if( buf[3] == 0x08 && buf[2] == 0xf2 && - buf[1] == 0xa6 && buf[0] == 0xb6 ) - /* INTEL-order VIPS image. - */ - return( 1 ); + load->flags = VIPS_FILE_PARTIAL; + + if( vips__file_magic( file->filename ) == VIPS_MAGIC_INTEL ) { + printf( "vips_file_load_vips_get_flags: " + "%s is intel, setting bigendian\n", + file->filename ); + load->flags |= VIPS_FILE_BIGENDIAN; } return( 0 ); @@ -82,33 +75,45 @@ vips_file_load_vips_is_a( const char *filename ) static int vips_file_load_vips_header( VipsFileLoad *load ) { -} + VipsFile *file = VIPS_FILE( load ); + VipsImage *out; + VipsImage *out2; -static int -vips_file_load_vips_load( VipsFileLoad *load ) -{ + if( !(out2 = vips_image_new_from_file( file->filename )) ) + return( -1 ); + + /* Remove the @out that's there now. + */ + g_object_get( load, "out", &out, NULL ); + g_object_set( load, "out", out2, NULL ); + + /* Unref after we install the new out to make sure load isn't + * disposed. + */ + g_object_unref( out ); + g_object_unref( out ); + + return( 0 ); } static const char *vips_suffs[] = { ".v", NULL }; static void -vips_file_load_jpeg_class_init( VipsFileLoadJpegClass *class ) +vips_file_load_vips_class_init( VipsFileLoadVipsClass *class ) { - GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; - VipsFileClass *file_class = (VipsLoadClass *) class; + VipsFileClass *file_class = (VipsFileClass *) class; VipsFileLoadClass *load_class = (VipsFileLoadClass *) class; object_class->nickname = "vipsload"; object_class->description = _( "load vips from file" ); - object_class->build = vips_file_load_vips_build; file_class->suffs = vips_suffs; load_class->is_a = vips_file_load_vips_is_a; + load_class->get_flags = vips_file_load_vips_get_flags; load_class->header = vips_file_load_vips_header; - load_class->load = vips_file_load_vips_load; - + load_class->load = NULL; } static void diff --git a/libvips/file/vipssave.c b/libvips/file/vipssave.c index 1f87efa0..57080ea1 100644 --- a/libvips/file/vipssave.c +++ b/libvips/file/vipssave.c @@ -61,7 +61,7 @@ vips_file_save_vips_build( VipsObject *object ) build( object ) ) return( -1 ); - if( vips_image_write_to_file( save->in, file->filename ) ) + if( vips_image_write_to_file( save->ready, file->filename ) ) return( -1 ); return( 0 ); @@ -105,7 +105,6 @@ vips_file_save_vips_class_init( VipsFileSaveVipsClass *class ) save_class->saveable = VIPS_SAVEABLE_ANY; save_class->format_table = vips_bandfmt_vips; - } static void diff --git a/libvips/include/vips/file.h b/libvips/include/vips/file.h index bd8f596a..3f6e962b 100644 --- a/libvips/include/vips/file.h +++ b/libvips/include/vips/file.h @@ -104,7 +104,7 @@ void *vips_file_map( const char *base, VipsSListMap2Fn fn, void *a, void *b ); /* Image file properties. */ typedef enum { - VIPS_FILE_NONE = 0, /* No flags set */ + VIPS_FILE_NONE = 0, /* No flags set */ VIPS_FILE_PARTIAL = 1, /* Lazy read OK (eg. tiled tiff) */ VIPS_FILE_BIGENDIAN = 2 /* Most-significant byte first */ } VipsFileFlags; @@ -145,11 +145,13 @@ typedef struct _VipsFileLoadClass { */ int (*get_flags)( VipsFileLoad * ); - /* Read the header into @out. + /* Set the header fields in @out from @filename. If you can read the + * whole image as well with no performance cost (as with vipsload), + * leave ->load() NULL. */ int (*header)( VipsFileLoad * ); - /* Read the whole image into real. It gets copied to out later. + /* Read the whole image into @real. It gets copied to @out later. */ int (*load)( VipsFileLoad * ); diff --git a/libvips/include/vips/internal.h b/libvips/include/vips/internal.h index 7cc16db7..b69a4505 100644 --- a/libvips/include/vips/internal.h +++ b/libvips/include/vips/internal.h @@ -107,6 +107,7 @@ void vips__read_4byte( int msb_first, unsigned char *to, unsigned char **from ); void vips__read_2byte( int msb_first, unsigned char *to, unsigned char **from ); void vips__write_4byte( unsigned char **to, unsigned char *from ); void vips__write_2byte( unsigned char **to, unsigned char *from ); +guint32 vips__file_magic( const char *filename ); int vips__has_extension_block( VipsImage *im ); void *vips__read_extension_block( VipsImage *im, int *size ); int vips__write_extension_block( VipsImage *im, void *buf, int size ); diff --git a/libvips/iofuncs/generate.c b/libvips/iofuncs/generate.c index 08568665..a5ee7210 100644 --- a/libvips/iofuncs/generate.c +++ b/libvips/iofuncs/generate.c @@ -682,7 +682,7 @@ vips_image_generate( VipsImage *image, */ vips_error( "VipsImage", _( "unable to output to a %s image" ), - VIPS_ENUM_NICK( VIPS_TYPE_DEMAND_STYLE, + VIPS_ENUM_NICK( VIPS_TYPE_IMAGE_TYPE, image->dtype ) ); return( -1 ); } diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c index 97bbc77b..d24d979d 100644 --- a/libvips/iofuncs/image.c +++ b/libvips/iofuncs/image.c @@ -460,220 +460,30 @@ vips_image_rewind( VipsObject *object ) image->mode = mode; } -static gboolean -vips_format_is_vips( VipsFormatClass *format ) -{ - return( strcmp( VIPS_OBJECT_CLASS( format )->nickname, "vips" ) == 0 ); -} - -/* Lazy open. - */ - -/* What we track during a delayed open. - */ -typedef struct { - VipsImage *image; - VipsFormatClass *format;/* Read in pixels with this */ - char *filename; /* Get pixels from here */ - gboolean disc; /* Read via disc requested */ - - VipsImage *real; /* The real decompressed image */ -} Lazy; - -static void -lazy_free_cb( VipsImage *image, Lazy *lazy ) -{ - VIPS_DEBUG_MSG( "lazy_free: %p \"%s\"\n", lazy, lazy->filename ); - - g_free( lazy->filename ); - VIPS_UNREF( lazy->real ); - g_free( lazy ); -} - -static Lazy * -lazy_new( VipsImage *image, - VipsFormatClass *format, const char *filename, gboolean disc ) -{ - Lazy *lazy; - - lazy = g_new( Lazy, 1 ); - VIPS_DEBUG_MSG( "lazy_new: %p \"%s\"\n", lazy, filename ); - lazy->image = image; - lazy->format = format; - lazy->filename = g_strdup( filename ); - lazy->disc = disc; - lazy->real = NULL; - g_signal_connect( image, "close", G_CALLBACK( lazy_free_cb ), lazy ); - - return( lazy ); -} - -static size_t -disc_threshold( void ) -{ - static gboolean done = FALSE; - static size_t threshold; - - if( !done ) { - const char *env; - - done = TRUE; - - /* 100mb default. - */ - threshold = 100 * 1024 * 1024; - - if( (env = g_getenv( "IM_DISC_THRESHOLD" )) ) - threshold = vips__parse_size( env ); - - if( vips__disc_threshold ) - threshold = vips__parse_size( vips__disc_threshold ); - - VIPS_DEBUG_MSG( "disc_threshold: %zd bytes\n", threshold ); - } - - return( threshold ); -} - -/* Make the real underlying image: either a direct disc file, or a temp file - * somewhere. - */ -static VipsImage * -lazy_real_image( Lazy *lazy ) -{ - VipsImage *real; - - /* We open via disc if: - * - 'disc' is set - * - disc_threshold() has not been set to zero - * - the format does not support lazy read - * - the uncompressed image will be larger than disc_threshold() - */ - real = NULL; - if( lazy->disc && - disc_threshold() && - !(vips_format_get_flags( lazy->format, lazy->filename ) & - VIPS_FORMAT_PARTIAL) && - VIPS_IMAGE_SIZEOF_IMAGE( lazy->image ) > disc_threshold() ) - if( !(real = vips_image_new_disc_temp( "%s.v" )) ) - return( NULL ); - - /* Otherwise, fall back to a "p". - */ - if( !real && - !(real = vips_image_new()) ) - return( NULL ); - - return( real ); -} - -/* Our start function ... do the lazy open, if necessary, and return a region - * on the new image. - */ -static void * -open_lazy_start( VipsImage *out, void *a, void *dummy ) -{ - Lazy *lazy = (Lazy *) a; - - if( !lazy->real ) { - if( !(lazy->real = lazy_real_image( lazy )) || - lazy->format->load( lazy->filename, lazy->real ) || - vips_image_pio_input( lazy->real ) ) { - VIPS_UNREF( lazy->real ); - return( NULL ); - } - } - - return( vips_region_new( lazy->real ) ); -} - -/* Just copy. - */ -static int -open_lazy_generate( VipsRegion *or, - void *seq, void *a, void *b, gboolean *stop ) -{ - VipsRegion *ir = (VipsRegion *) seq; - - VipsRect *r = &or->valid; - - /* Ask for input we need. - */ - if( vips_region_prepare( ir, r ) ) - return( -1 ); - - /* Attach output region to that. - */ - if( vips_region_region( or, ir, r, r->left, r->top ) ) - return( -1 ); - - return( 0 ); -} - -/* Lazy open ... init the header with the first OpenLazyFn, delay actually - * decoding pixels with the second OpenLazyFn until the first generate(). - */ -static int -vips_image_open_lazy( VipsImage *image, - VipsFormatClass *format, const char *filename, gboolean disc ) -{ - Lazy *lazy; - - lazy = lazy_new( image, format, filename, disc ); - - /* Read header fields to init the return image. THINSTRIP since this is - * probably a disc file. We can't tell yet whether we will be opening - * to memory, sadly, so we can't suggest ANY. - */ - if( format->header( filename, image ) ) - return( -1 ); - vips_demand_hint( image, VIPS_DEMAND_STYLE_THINSTRIP, NULL ); - - /* Then 'start' creates the real image and 'gen' paints 'out' with - * pixels from the real image on demand. - */ - if( vips_image_generate( image, - open_lazy_start, open_lazy_generate, vips_stop_one, - lazy, NULL ) ) - return( -1 ); - - return( 0 ); -} - -/* Lazy save. +/* Delayed save. */ /* If we write to (eg.) TIFF, actually do the write - * to a "p" and on "written" do im_vips2tiff() or whatever. Track save - * parameters here. + * to a "p" and on "written" do im_vips2tiff() or whatever. */ -typedef struct { - int (*save_fn)(); /* Save function */ - char *filename; /* Save args */ -} SaveBlock; /* From "written" callback: invoke a delayed save. */ static void -vips_image_save_cb( VipsImage *image, int *result, SaveBlock *sb ) +vips_image_save_cb( VipsImage *image, int *result, char *filename ) { - if( sb->save_fn( image, sb->filename ) ) + if( vips_file_write( image, filename, NULL ) ) *result = -1; - g_free( sb->filename ); - g_free( sb ); + g_free( filename ); } static void -vips_attach_save( VipsImage *image, int (*save_fn)(), const char *filename ) +vips_attach_save( VipsImage *image, const char *filename ) { - SaveBlock *sb; - - sb = g_new( SaveBlock, 1 ); - sb->save_fn = save_fn; - sb->filename = g_strdup( filename ); g_signal_connect( image, "written", - G_CALLBACK( vips_image_save_cb ), sb ); + G_CALLBACK( vips_image_save_cb ), + g_strdup( filename ) ); } /* Progress feedback. @@ -756,7 +566,7 @@ vips_image_build( VipsObject *object ) const char *filename = image->filename; const char *mode = image->mode; - const char *file_op; + guint32 magic; size_t sizeof_image; VIPS_DEBUG_MSG( "vips_image_build: %p\n", image ); @@ -767,62 +577,84 @@ vips_image_build( VipsObject *object ) /* Parse the mode string. */ switch( mode[0] ) { - case 'r': - if( !(file_op = vips_file_find_load( filename )) ) + case 'v': + /* Used by 'r' for native open of vips, see below. + */ + if( vips_image_open_input( image ) ) return( -1 ); - if( vips_format_is_vips( format ) ) { + break; + + case 'r': + if( (magic = vips__file_magic( filename )) ) { /* We may need to byteswap. */ - VipsFormatFlags flags = - vips_format_get_flags( format, filename ); - gboolean native = (flags & VIPS_FORMAT_BIGENDIAN) == - vips_amiMSBfirst(); + guint32 us = vips_amiMSBfirst() ? + VIPS_MAGIC_INTEL : VIPS_MAGIC_SPARC; - if( native ) { + if( magic == us ) { + /* Native open. + */ if( vips_image_open_input( image ) ) return( -1 ); - - if( mode[1] == 'w' ) - image->dtype = VIPS_IMAGE_MMAPINRW; } else { - VipsImage *x; + VipsImage *t; + VipsImage *t2; - if( !(x = vips_image_new()) ) + /* Open the image in t, then byteswap to this + * image. + */ + if( !(t = vips_image_new_mode( filename, + "v" )) ) return( -1 ); - vips_object_local( image, x ); - if( vips_image_open_input( x ) ) + + if( vips_copy( t, &t2, + "swap", TRUE, + NULL ) ) { + g_object_unref( t ); return( -1 ); + } + g_object_unref( t ); + image->dtype = VIPS_IMAGE_PARTIAL; - if( im_copy_swap( x, image ) ) + if( vips_image_write( t2, image ) ) { + g_object_unref( t2 ); return( -1 ); + } + g_object_unref( t2 ); } } else { - /* Make this a partial, generate into it from the - * converter. - */ - image->dtype = VIPS_IMAGE_PARTIAL; + VipsImage *t; - if( vips_image_open_lazy( image, format, - filename, mode[1] == 'd' ) ) + if( vips_file_read( filename, &t, NULL ) ) return( -1 ); + + image->dtype = VIPS_IMAGE_PARTIAL; + if( vips_image_write( t, image ) ) { + g_object_unref( t ); + return( -1 ); + } + g_object_unref( t ); } break; case 'w': - if( !(format = vips_format_for_name( filename )) ) +{ + const char *file_op; + + if( !(file_op = vips_file_find_save( filename )) ) return( -1 ); - if( vips_format_is_vips( format ) ) + if( strcmp( file_op, "VipsFileSaveVips" ) == 0 ) image->dtype = VIPS_IMAGE_OPENOUT; else { image->dtype = VIPS_IMAGE_PARTIAL; - vips_attach_save( image, - format->save, filename ); + vips_attach_save( image, filename ); } +} break; case 't': @@ -1964,7 +1796,7 @@ vips_image_write_line( VipsImage *image, int ypos, PEL *linebuffer ) default: vips_error( "VipsImage", _( "unable to output to a %s image" ), - VIPS_ENUM_STRING( VIPS_TYPE_DEMAND_STYLE, + VIPS_ENUM_STRING( VIPS_TYPE_IMAGE_TYPE, image->dtype ) ); return( -1 ); } diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index 90bce3ad..fcfe2a91 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -1231,19 +1231,61 @@ vips_object_set_argument_from_string( VipsObject *object, g_assert( argument_class->flags & VIPS_ARGUMENT_INPUT ); - if( g_type_is_a( otype, VIPS_TYPE_OBJECT ) && - (oclass = g_type_class_ref( otype )) ) { - VipsObject *object; + if( g_type_is_a( otype, VIPS_TYPE_IMAGE ) && + (oclass = g_type_class_ref( VIPS_TYPE_FILE_LOAD )) ) { + VipsObject *new_object; + VipsImage *out; - if( !(object = vips_object_new_from_string( oclass, value )) ) + /* Use VipsFile to build images, then pull @out from it and + * use that to set the value. + */ + if( !(new_object = + vips_object_new_from_string( oclass, value )) ) return( -1 ); + if( vips_object_build( new_object ) ) { + g_object_unref( new_object ); + return( -1 ); + } + + g_object_get( new_object, "out", &out, NULL ); + + /* Getting @out will have upped it's count and we want to + * hold the only ref to it. + */ + g_object_unref( out ); + + /* @out holds a ref to new_object, we can drop ours. + */ + g_object_unref( new_object ); + + g_value_init( &gvalue, VIPS_TYPE_IMAGE ); + g_value_set_object( &gvalue, out ); + + /* Setting gvalue will have upped @out's count again, + * go back to 1 so that gvalue has the only ref. + */ + g_object_unref( out ); + } + else if( g_type_is_a( otype, VIPS_TYPE_OBJECT ) && + (oclass = g_type_class_ref( otype )) ) { + VipsObject *new_object; + + if( !(new_object = + vips_object_new_from_string( oclass, value )) ) + return( -1 ); + + if( vips_object_build( new_object ) ) { + g_object_unref( new_object ); + return( -1 ); + } + g_value_init( &gvalue, G_TYPE_OBJECT ); - g_value_set_object( &gvalue, object ); + g_value_set_object( &gvalue, new_object ); /* The GValue now has a ref, we can drop ours. */ - g_object_unref( object ); + g_object_unref( new_object ); } else if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) ) { gboolean b; @@ -1375,7 +1417,30 @@ vips_object_get_argument_to_string( VipsObject *object, g_assert( argument_class->flags & VIPS_ARGUMENT_OUTPUT ); - if( g_type_is_a( otype, VIPS_TYPE_OBJECT ) && + if( g_type_is_a( otype, VIPS_TYPE_IMAGE ) && + (oclass = g_type_class_ref( VIPS_TYPE_FILE_SAVE )) ) { + VipsObject *new_object; + VipsImage *in; + + /* Use VipsFile to make a saver, set 'in' on that and run + * build to make it write. + */ + if( !(new_object = + vips_object_new_from_string( oclass, arg )) ) + return( -1 ); + + g_object_get( object, name, &in, NULL ); + g_object_set( new_object, "in", in, NULL ); + g_object_unref( in ); + + if( vips_object_build( new_object ) ) { + g_object_unref( new_object ); + return( -1 ); + } + + g_object_unref( new_object ); + } + else if( g_type_is_a( otype, VIPS_TYPE_OBJECT ) && (oclass = g_type_class_ref( otype )) && oclass->output_to_arg ) { VipsObject *value; @@ -1538,11 +1603,6 @@ vips_object_new_from_string( VipsObjectClass *object_class, const char *p ) } } - if( vips_object_build( object ) ) { - g_object_unref( object ); - return( NULL ); - } - return( object ); } diff --git a/libvips/iofuncs/vips.c b/libvips/iofuncs/vips.c index 1603ccc4..a86df9af 100644 --- a/libvips/iofuncs/vips.c +++ b/libvips/iofuncs/vips.c @@ -218,6 +218,19 @@ vips__write_2byte( unsigned char **to, unsigned char *from ) *to += 2; } +guint32 +vips__file_magic( const char *filename ) +{ + guint32 magic; + + if( vips__get_bytes( filename, (unsigned char *) &magic, 4 ) && + (magic == VIPS_MAGIC_INTEL || + magic == VIPS_MAGIC_SPARC ) ) + return( magic ); + + return( 0 ); +} + /* offset, read, write functions. */ typedef struct _FieldIO {