From f671088ff2d0ff117882d0bd2e592fb317a04ec3 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Wed, 23 Nov 2011 14:03:11 +0000 Subject: [PATCH] hackery on new format system --- TODO | 9 + libvips/format/format.c | 389 +++++---------------- libvips/format/old_format.c | 618 ++++++++++++++++++++++++++++++++++ libvips/include/vips/format.h | 138 ++++++-- 4 files changed, 827 insertions(+), 327 deletions(-) create mode 100644 libvips/format/old_format.c diff --git a/TODO b/TODO index c1faa406..0a8df569 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,12 @@ +- do we need separate classes for load and save? + + tiff, for example, will need different props for load and save operations + + since they are optional I guess we could combine them + + + + - vipsimage should be cached too, eg. VipsImage *a = vips_image_new_from_file( "poop.jpg" ); diff --git a/libvips/format/format.c b/libvips/format/format.c index 0c002d7b..daa76cd1 100644 --- a/libvips/format/format.c +++ b/libvips/format/format.c @@ -227,10 +227,9 @@ G_DEFINE_TYPE( VipsFormatTiff, vips_format_tiff, VIPS_TYPE_FORMAT ); static void * format_add_class( VipsFormatClass *format, GSList **formats ) { - if( !G_TYPE_IS_ABSTRACT( G_OBJECT_CLASS_TYPE( format ) ) ) - /* Append so we don't reverse the list of formats. - */ - *formats = g_slist_append( *formats, format ); + /* Append so we don't reverse the list of formats. + */ + *formats = g_slist_append( *formats, format ); return( NULL ); } @@ -243,11 +242,12 @@ format_compare( VipsFormatClass *a, VipsFormatClass *b ) /** * vips_format_map: + * @base: base class to search below (eg. "VipsFormatLoad") * @fn: function to apply to each #VipsFormatClass * @a: user data * @b: user data * - * Apply a function to every %VipsFormatClass that VIPS knows about. Formats + * Apply a function to every #VipsFormatClass that VIPS knows about. Formats * are presented to the function in priority order. * * Like all VIPS map functions, if @fn returns %NULL, iteration continues. If @@ -259,13 +259,13 @@ format_compare( VipsFormatClass *a, VipsFormatClass *b ) * Returns: the result of iteration */ void * -vips_format_map( VipsSListMap2Fn fn, void *a, void *b ) +vips_format_map( const char *base, VipsSListMap2Fn fn, void *a, void *b ) { GSList *formats; void *result; formats = NULL; - (void) vips_class_map_all( g_type_from_name( "VipsFormat" ), + (void) vips_class_map_all( g_type_from_name( base ), (VipsClassMapFn) format_add_class, (void *) &formats ); formats = g_slist_sort( formats, (GCompareFunc) format_compare ); @@ -300,8 +300,93 @@ vips_format_print_class( VipsObjectClass *object_class, VipsBuf *buf ) vips_buf_appends( buf, ") " ); } + vips_buf_appends( buf, "priority=%d ", class->priority ); + if( class->is_a ) vips_buf_appends( buf, "is_a " ); +} + +static void +vips_format_class_init( VipsFormatClass *class ) +{ + VipsObjectClass *object_class = (VipsObjectClass *) class; + + object_class->nickname = "format"; + object_class->description = _( "file format support" ); + object_class->print_class = vips_format_print_class; +} + +static void +vips_format_init( VipsFormat *object ) +{ +} + +/* Abstract base class for image load. + */ + +G_DEFINE_ABSTRACT_TYPE( VipsFormatLoad, vips_formats_load, VIPS_TYPE_FORMAT ); + +static void +vips_format_load_print_class( VipsObjectClass *object_class, VipsBuf *buf ) +{ + VipsFormatLoadClass *class = VIPS_FORMAT_LOAD_CLASS( object_class ); + const char **p; + + VIPS_OBJECT_CLASS( vips_format_load_parent_class )-> + print_class( object_class, buf ); + vips_buf_appends( buf, ", " ); + + if( class->header ) + vips_buf_appends( buf, "header " ); + if( class->load ) + vips_buf_appends( buf, "load " ); + if( class->get_flags ) + vips_buf_appends( buf, "get_flags " ); +} + +static void +vips_format_load_class_init( VipsFormatLoadClass *class ) +{ + VipsObjectClass *object_class = (VipsObjectClass *) class; + + object_class->nickname = "formatload"; + object_class->description = _( "format loaders" ); + object_class->print_class = vips_format_load_print_class; +} + +static void +vips_format_load_init( VipsFormatLoad *object ) +{ +} + +/* Abstract base class for image savers. + */ + +G_DEFINE_ABSTRACT_TYPE( VipsFormatSave, vips_format_save, VIPS_TYPE_FORMAT ); + +static void +vips_format_print_class( VipsObjectClass *object_class, VipsBuf *buf ) +{ + VipsFormatClass *class = VIPS_FORMAT_CLASS( object_class ); + const char **p; + + VIPS_OBJECT_CLASS( vips_format_parent_class )-> + print_class( object_class, buf ); + vips_buf_appends( buf, ", " ); + + if( class->suffs ) { + vips_buf_appends( buf, "(" ); + for( p = class->suffs; *p; p++ ) { + vips_buf_appendf( buf, "%s", *p ); + if( p[1] ) + vips_buf_appends( buf, ", " ); + } + vips_buf_appends( buf, ") " ); + } + + if( class->is_a ) + vips_buf_appends( buf, "is_a " ); + if( class->header ) vips_buf_appends( buf, "header " ); if( class->load ) @@ -326,293 +411,3 @@ static void vips_format_init( VipsFormat *object ) { } - -/** - * vips_format_get_flags: - * @format: format to test - * @filename: file to test - * - * Get a set of flags for this file. - * - * Returns: flags for this format and file - */ -VipsFormatFlags -vips_format_get_flags( VipsFormatClass *format, const char *filename ) -{ - return( format->get_flags ? format->get_flags( filename ) : 0 ); -} - -/* VIPS format class. - */ - -static const char *vips_suffs[] = { ".v", NULL }; - -static int -isvips( const char *filename ) -{ - unsigned char buf[4]; - - 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 ); - } - - return( 0 ); -} - -static int -file2vips( const char *filename, VipsImage *out ) -{ - VipsImage *t; - - if( !(t = vips_image_new_from_file( filename )) ) - return( -1 ); - if( vips_image_write( t, out ) ) { - g_object_unref( t ); - return( -1 ); - } - g_object_unref( t ); - - return( 0 ); -} - -static VipsFormatFlags -vips_flags( const char *filename ) -{ - VipsFormatFlags flags; - unsigned char buf[4]; - - flags = VIPS_FORMAT_PARTIAL; - - if( vips__get_bytes( filename, buf, 4 ) && - buf[0] == 0x08 && - buf[1] == 0xf2 && - buf[2] == 0xa6 && - buf[3] == 0xb6 ) - flags |= VIPS_FORMAT_BIGENDIAN; - - return( flags ); -} - -/* Vips format adds no new members. - */ -typedef VipsFormat VipsFormatVips; -typedef VipsFormatClass VipsFormatVipsClass; - -static void -vips_format_vips_class_init( VipsFormatVipsClass *class ) -{ - VipsObjectClass *object_class = (VipsObjectClass *) class; - VipsFormatClass *format_class = (VipsFormatClass *) class; - - object_class->nickname = "vips"; - object_class->description = _( "VIPS" ); - - format_class->is_a = isvips; - format_class->header = file2vips; - format_class->load = file2vips; - format_class->save = vips_image_write_to_file; - format_class->get_flags = vips_flags; - format_class->suffs = vips_suffs; -} - -static void -vips_format_vips_init( VipsFormatVips *object ) -{ -} - -G_DEFINE_TYPE( VipsFormatVips, vips_format_vips, VIPS_TYPE_FORMAT ); - -/* Called on startup: register the base vips formats. - */ -void -vips__format_init( void ) -{ - extern GType vips_format_csv_get_type(); - extern GType vips_format_ppm_get_type(); - extern GType vips_format_analyze_get_type(); - extern GType vips_format_rad_get_type(); - - vips_format_vips_get_type(); -#ifdef HAVE_JPEG - extern GType vips_format_jpeg_get_type(); - vips_format_jpeg_get_type(); -#endif /*HAVE_JPEG*/ -#ifdef HAVE_PNG - extern GType vips_format_png_get_type(); - vips_format_png_get_type(); -#endif /*HAVE_PNG*/ - vips_format_csv_get_type(); - vips_format_ppm_get_type(); - vips_format_analyze_get_type(); -#ifdef HAVE_OPENEXR - extern GType vips_format_exr_get_type(); - vips_format_exr_get_type(); -#endif /*HAVE_OPENEXR*/ -#ifdef HAVE_MATIO - extern GType vips_format_mat_get_type(); - vips_format_mat_get_type(); -#endif /*HAVE_MATIO*/ -#ifdef HAVE_CFITSIO - extern GType vips_format_fits_get_type(); - vips_format_fits_get_type(); -#endif /*HAVE_CFITSIO*/ - vips_format_rad_get_type(); -#ifdef HAVE_MAGICK - extern GType vips_format_magick_get_type(); - vips_format_magick_get_type(); -#endif /*HAVE_MAGICK*/ -#ifdef HAVE_TIFF - extern GType vips_format_tiff_get_type(); - vips_format_tiff_get_type(); -#endif /*HAVE_TIFF*/ -} - -/* Can this format open this file? - */ -static void * -format_for_file_sub( VipsFormatClass *format, - const char *name, const char *filename ) -{ - if( format->is_a ) { - if( format->is_a( filename ) ) - return( format ); - } - else if( vips_filename_suffix_match( filename, format->suffs ) ) - return( format ); - - return( NULL ); -} - -/** - * vips_format_for_file: - * @filename: file to find a format for - * - * Searches for a format you could use to load a file. - * - * See also: vips_format_read(), vips_format_for_name(). - * - * Returns: a format on success, %NULL on error - */ -VipsFormatClass * -vips_format_for_file( const char *filename ) -{ - char name[FILENAME_MAX]; - char options[FILENAME_MAX]; - VipsFormatClass *format; - - /* Break any options off the name ... eg. "fred.tif:jpeg,tile" - * etc. - */ - vips_filename_split( filename, name, options ); - - if( !vips_existsf( "%s", name ) ) { - vips_error( "VipsFormat", _( "file \"%s\" not found" ), name ); - return( NULL ); - } - - if( !(format = (VipsFormatClass *) vips_format_map( - (VipsSListMap2Fn) format_for_file_sub, - (void *) filename, (void *) name )) ) { - vips_error( "VipsFormat", - _( "file \"%s\" not a known format" ), name ); - return( NULL ); - } - - return( format ); -} - -/* Can we write this filename with this format? Ignore formats without a save - * method. - */ -static void * -format_for_name_sub( VipsFormatClass *format, const char *name ) -{ - if( format->save && - vips_filename_suffix_match( name, format->suffs ) ) - return( format ); - - return( NULL ); -} - -/** - * vips_format_for_name: - * @filename: name to find a format for - * - * Searches for a format you could use to save a file. - * - * See also: vips_format_write(), vips_format_for_file(). - * - * Returns: a format on success, %NULL on error - */ -VipsFormatClass * -vips_format_for_name( const char *filename ) -{ - VipsFormatClass *format; - - if( !(format = (VipsFormatClass *) vips_format_map( - (VipsSListMap2Fn) format_for_name_sub, - (void *) filename, NULL )) ) { - vips_error( "VipsFormat", - _( "\"%s\" is not a supported image format." ), - filename ); - - return( NULL ); - } - - return( format ); -} - -/** - * vips_format_read: - * @filename: file to load - * @out: write the file to this image - * - * Searches for a format for this file, then loads the file into @out. - * - * See also: vips_format_write(). - * - * Returns: 0 on success, -1 on error - */ -int -vips_format_read( const char *filename, IMAGE *out ) -{ - VipsFormatClass *format; - - if( !(format = vips_format_for_file( filename )) || - format->load( filename, out ) ) - return( -1 ); - - return( 0 ); -} - -/** - * vips_format_write: - * @in: image to write - * @filename: file to write to - * - * Searches for a format for this name, then saves @im to it. - * - * See also: vips_format_read(). - * - * Returns: 0 on success, -1 on error - */ -int -vips_format_write( IMAGE *in, const char *filename ) -{ - VipsFormatClass *format; - - if( !(format = vips_format_for_name( filename )) || - format->save( in, filename ) ) - return( -1 ); - - return( 0 ); -} diff --git a/libvips/format/old_format.c b/libvips/format/old_format.c new file mode 100644 index 00000000..6ca3d330 --- /dev/null +++ b/libvips/format/old_format.c @@ -0,0 +1,618 @@ +/* VIPS function dispatch tables for image format load/save. + */ + +/* + + This file is part of VIPS. + + VIPS is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + */ + +/* + + These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /*HAVE_CONFIG_H*/ +#include + +#include + +#include +#include + +/** + * SECTION: format + * @short_description: load and save in a variety of formats + * @stability: Stable + * @see_also: image + * @include: vips/vips.h + * + * VIPS has a simple system for representing image load and save operations in + * a generic way. + * + * You can ask for a loader for a certain file or select a saver based on a + * filename. Once you have found a format, you can use it to load a file of + * that type, save an image to a file of that type, query files for their type + * and fields, and ask for supported features. You can also call the + * converters directly, if you like. + * + * If you define a new format, support for + * it automatically appears in all VIPS user-interfaces. It will also be + * transparently supported by vips_image_new_from_file() and friends. + * + * VIPS comes with VipsFormat for TIFF, JPEG, PNG, Analyze, PPM, OpenEXR, CSV, + * Matlab, Radiance, RAW, VIPS and one that wraps libMagick. + */ + +/** + * VipsFormatFlags: + * @VIPS_FORMAT_NONE: no flags set + * @VIPS_FORMAT_PARTIAL: the image may be read lazilly + * @VIPS_FORMAT_BIGENDIAN: image pixels are most-significant byte first + * + * Some hints about the image loader. + * + * @VIPS_FORMAT_PARTIAL means that the image can be read directly from the + * file without needing to be unpacked to a temporary image first. + * + * @VIPS_FORMAT_BIGENDIAN means that image pixels are most-significant byte + * first. Depending on the native byte order of the host machine, you may + * need to swap bytes. See copy_swap(). + */ + +/** + * VipsFormat: + * + * #VipsFormat has these virtual methods: + * + * |[ + * typedef struct _VipsFormatClass { + * VipsObjectClass parent_class; + * + * gboolean (*is_a)( const char *filename ); + * int (*header)( const char *filename, IMAGE *out ); + * int (*load)( const char *filename, IMAGE *out ); + * int (*save)( IMAGE *in, const char *filename ); + * VipsFormatFlags (*get_flags)( const char *filename ); + * int priority; + * const char **suffs; + * } VipsFormatClass; + * ]| + * + * Add a new format to VIPS by subclassing VipsFormat. Subclasses need to + * implement at least load() or save(). + * + * These members are: + * + * + * + * + * is_a() This function should return %TRUE if the file + * contains an image of this type. If you don't define this function, VIPS + * will use the list of suffixes you supply instead. + * + * + * + * + * header() This function should load the image header, + * but not load any pixel data. If you don't define it, VIPS will use your + * load() method instead. Return 0 for success, -1 for error, setting + * vips_error(). + * + * + * + * + * load() This function should load the image, or perhaps use + * vips_image_generate() to + * attach something to load sections of the image on demand. + * Users can embed + * load options in the filename, see (for example) im_jpeg2vips(). + * If you don't + * define this method, you can still define save() and have a save-only + * format. + * Return 0 for success, -1 for error, setting + * im_error(). + * + * + * + * + * save() This function should save the image to the file. + * Users can embed + * save options in the filename, see (for example) im_vips2tiff(). + * If you don't + * define this method, you can still define load() and have a load-only + * format. + * Return 0 for success, -1 for error, setting + * im_error(). + * + * + * + * + * get_flags() This function should return a hint about the properties of this + * loader on this file. If you don't define it, users will always see '0', or + * no flags. + * + * + * + * + * priority Where this format should fit in this + * list of + * supported formats. 0 is a sensible value for most formats. Set a negative + * value if you want to be lower on the list, positive to move up. + * + * + * + * + * suffs A %NULL-terminated list of possible file + * name + * suffixes, for example: + * |[ + * static const char *tiff_suffs[] = { ".tif", ".tiff", NULL }; + * ]| + * The suffix list is used to select a format to save a file in, and to pick a + * loader if you don't define is_a(). + * + * + * + * + * You should also define nickname and + * description in #VipsObject. + * + * At the command-line, use: + * + * |[ + * vips --list classes | grep Format + * ]| + * + * To see a list of all the supported formats. + * + * For example, the TIFF format is defined like this: + * +|[ +typedef VipsFormat VipsFormatTiff; +typedef VipsFormatClass VipsFormatTiffClass; + +static void +vips_format_tiff_class_init( VipsFormatTiffClass *class ) +{ + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsFormatClass *format_class = (VipsFormatClass *) class; + + object_class->nickname = "tiff"; + object_class->description = _( "TIFF" ); + + format_class->is_a = istiff; + format_class->header = tiff2vips_header; + format_class->load = im_tiff2vips; + format_class->save = im_vips2tiff; + format_class->get_flags = tiff_flags; + format_class->suffs = tiff_suffs; +} + +static void +vips_format_tiff_init( VipsFormatTiff *object ) +{ +} + +G_DEFINE_TYPE( VipsFormatTiff, vips_format_tiff, VIPS_TYPE_FORMAT ); +]| + * + * Then call vips_format_tiff_get_type() somewhere in your init code to link + * the format into VIPS (though of course the tiff format is linked in for you + * already). + * + */ + +/* To iterate over supported formats, we build a temp list of subclasses of + * VipsFormat, sort by priority, iterate, and free. + */ + +static void * +format_add_class( VipsFormatClass *format, GSList **formats ) +{ + /* Append so we don't reverse the list of formats. + */ + *formats = g_slist_append( *formats, format ); + + return( NULL ); +} + +static gint +format_compare( VipsFormatClass *a, VipsFormatClass *b ) +{ + return( b->priority - a->priority ); +} + +/** + * vips_format_map: + * @base: base class to search below (eg. "VipsFormatLoad") + * @fn: function to apply to each #VipsFormatClass + * @a: user data + * @b: user data + * + * Apply a function to every #VipsFormatClass that VIPS knows about. Formats + * are presented to the function in priority order. + * + * Like all VIPS map functions, if @fn returns %NULL, iteration continues. If + * it returns non-%NULL, iteration terminates and that value is returned. The + * map function returns %NULL if all calls return %NULL. + * + * See also: vips_slist_map(). + * + * Returns: the result of iteration + */ +void * +vips_format_map( const char *base, VipsSListMap2Fn fn, void *a, void *b ) +{ + GSList *formats; + void *result; + + formats = NULL; + (void) vips_class_map_all( g_type_from_name( base ), + (VipsClassMapFn) format_add_class, (void *) &formats ); + + formats = g_slist_sort( formats, (GCompareFunc) format_compare ); + result = vips_slist_map2( formats, fn, a, b ); + g_slist_free( formats ); + + return( result ); +} + +/* Abstract base class for image formats. + */ + +G_DEFINE_ABSTRACT_TYPE( VipsFormat, vips_format, VIPS_TYPE_OBJECT ); + +static void +vips_format_print_class( VipsObjectClass *object_class, VipsBuf *buf ) +{ + VipsFormatClass *class = VIPS_FORMAT_CLASS( object_class ); + const char **p; + + VIPS_OBJECT_CLASS( vips_format_parent_class )-> + print_class( object_class, buf ); + vips_buf_appends( buf, ", " ); + + if( class->suffs ) { + vips_buf_appends( buf, "(" ); + for( p = class->suffs; *p; p++ ) { + vips_buf_appendf( buf, "%s", *p ); + if( p[1] ) + vips_buf_appends( buf, ", " ); + } + vips_buf_appends( buf, ") " ); + } + + if( class->is_a ) + vips_buf_appends( buf, "is_a " ); + if( class->header ) + vips_buf_appends( buf, "header " ); + if( class->load ) + vips_buf_appends( buf, "load " ); + if( class->save ) + vips_buf_appends( buf, "save " ); + if( class->get_flags ) + vips_buf_appends( buf, "get_flags " ); +} + +static void +vips_format_class_init( VipsFormatClass *class ) +{ + VipsObjectClass *object_class = (VipsObjectClass *) class; + + object_class->nickname = "format"; + object_class->description = _( "VIPS file formats" ); + object_class->print_class = vips_format_print_class; +} + +static void +vips_format_init( VipsFormat *object ) +{ +} + +/** + * vips_format_get_flags: + * @format: format to test + * @filename: file to test + * + * Get a set of flags for this file. + * + * Returns: flags for this format and file + */ +VipsFormatFlags +vips_format_get_flags( VipsFormatClass *format, const char *filename ) +{ + return( format->get_flags ? format->get_flags( filename ) : 0 ); +} + +/* VIPS format class. + */ + +static const char *vips_suffs[] = { ".v", NULL }; + +static int +isvips( const char *filename ) +{ + unsigned char buf[4]; + + 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 ); + } + + return( 0 ); +} + +static int +file2vips( const char *filename, VipsImage *out ) +{ + VipsImage *t; + + if( !(t = vips_image_new_from_file( filename )) ) + return( -1 ); + if( vips_image_write( t, out ) ) { + g_object_unref( t ); + return( -1 ); + } + g_object_unref( t ); + + return( 0 ); +} + +static VipsFormatFlags +vips_flags( const char *filename ) +{ + VipsFormatFlags flags; + unsigned char buf[4]; + + flags = VIPS_FORMAT_PARTIAL; + + if( vips__get_bytes( filename, buf, 4 ) && + buf[0] == 0x08 && + buf[1] == 0xf2 && + buf[2] == 0xa6 && + buf[3] == 0xb6 ) + flags |= VIPS_FORMAT_BIGENDIAN; + + return( flags ); +} + +/* Vips format adds no new members. + */ +typedef VipsFormat VipsFormatVips; +typedef VipsFormatClass VipsFormatVipsClass; + +static void +vips_format_vips_class_init( VipsFormatVipsClass *class ) +{ + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsFormatClass *format_class = (VipsFormatClass *) class; + + object_class->nickname = "vips"; + object_class->description = _( "VIPS" ); + + format_class->is_a = isvips; + format_class->header = file2vips; + format_class->load = file2vips; + format_class->save = vips_image_write_to_file; + format_class->get_flags = vips_flags; + format_class->suffs = vips_suffs; +} + +static void +vips_format_vips_init( VipsFormatVips *object ) +{ +} + +G_DEFINE_TYPE( VipsFormatVips, vips_format_vips, VIPS_TYPE_FORMAT ); + +/* Called on startup: register the base vips formats. + */ +void +vips__format_init( void ) +{ + extern GType vips_format_csv_get_type(); + extern GType vips_format_ppm_get_type(); + extern GType vips_format_analyze_get_type(); + extern GType vips_format_rad_get_type(); + + vips_format_vips_get_type(); +#ifdef HAVE_JPEG + extern GType vips_format_jpeg_get_type(); + vips_format_jpeg_get_type(); +#endif /*HAVE_JPEG*/ +#ifdef HAVE_PNG + extern GType vips_format_png_get_type(); + vips_format_png_get_type(); +#endif /*HAVE_PNG*/ + vips_format_csv_get_type(); + vips_format_ppm_get_type(); + vips_format_analyze_get_type(); +#ifdef HAVE_OPENEXR + extern GType vips_format_exr_get_type(); + vips_format_exr_get_type(); +#endif /*HAVE_OPENEXR*/ +#ifdef HAVE_MATIO + extern GType vips_format_mat_get_type(); + vips_format_mat_get_type(); +#endif /*HAVE_MATIO*/ +#ifdef HAVE_CFITSIO + extern GType vips_format_fits_get_type(); + vips_format_fits_get_type(); +#endif /*HAVE_CFITSIO*/ + vips_format_rad_get_type(); +#ifdef HAVE_MAGICK + extern GType vips_format_magick_get_type(); + vips_format_magick_get_type(); +#endif /*HAVE_MAGICK*/ +#ifdef HAVE_TIFF + extern GType vips_format_tiff_get_type(); + vips_format_tiff_get_type(); +#endif /*HAVE_TIFF*/ +} + +/* Can this format open this file? + */ +static void * +format_for_file_sub( VipsFormatClass *format, + const char *name, const char *filename ) +{ + if( format->is_a ) { + if( format->is_a( filename ) ) + return( format ); + } + else if( vips_filename_suffix_match( filename, format->suffs ) ) + return( format ); + + return( NULL ); +} + +/** + * vips_format_for_file: + * @filename: file to find a format for + * + * Searches for a format you could use to load a file. + * + * See also: vips_format_read(), vips_format_for_name(). + * + * Returns: a format on success, %NULL on error + */ +VipsFormatClass * +vips_format_for_file( const char *filename ) +{ + char name[FILENAME_MAX]; + char options[FILENAME_MAX]; + VipsFormatClass *format; + + /* Break any options off the name ... eg. "fred.tif:jpeg,tile" + * etc. + */ + vips_filename_split( filename, name, options ); + + if( !vips_existsf( "%s", name ) ) { + vips_error( "VipsFormat", _( "file \"%s\" not found" ), name ); + return( NULL ); + } + + if( !(format = (VipsFormatClass *) vips_format_map( + (VipsSListMap2Fn) format_for_file_sub, + (void *) filename, (void *) name )) ) { + vips_error( "VipsFormat", + _( "file \"%s\" not a known format" ), name ); + return( NULL ); + } + + return( format ); +} + +/* Can we write this filename with this format? Ignore formats without a save + * method. + */ +static void * +format_for_name_sub( VipsFormatClass *format, const char *name ) +{ + if( format->save && + vips_filename_suffix_match( name, format->suffs ) ) + return( format ); + + return( NULL ); +} + +/** + * vips_format_for_name: + * @filename: name to find a format for + * + * Searches for a format you could use to save a file. + * + * See also: vips_format_write(), vips_format_for_file(). + * + * Returns: a format on success, %NULL on error + */ +VipsFormatClass * +vips_format_for_name( const char *filename ) +{ + VipsFormatClass *format; + + if( !(format = (VipsFormatClass *) vips_format_map( + (VipsSListMap2Fn) format_for_name_sub, + (void *) filename, NULL )) ) { + vips_error( "VipsFormat", + _( "\"%s\" is not a supported image format." ), + filename ); + + return( NULL ); + } + + return( format ); +} + +/** + * vips_format_read: + * @filename: file to load + * @out: write the file to this image + * + * Searches for a format for this file, then loads the file into @out. + * + * See also: vips_format_write(). + * + * Returns: 0 on success, -1 on error + */ +int +vips_format_read( const char *filename, IMAGE *out ) +{ + VipsFormatClass *format; + + if( !(format = vips_format_for_file( filename )) || + format->load( filename, out ) ) + return( -1 ); + + return( 0 ); +} + +/** + * vips_format_write: + * @in: image to write + * @filename: file to write to + * + * Searches for a format for this name, then saves @im to it. + * + * See also: vips_format_read(). + * + * Returns: 0 on success, -1 on error + */ +int +vips_format_write( IMAGE *in, const char *filename ) +{ + VipsFormatClass *format; + + if( !(format = vips_format_for_name( filename )) || + format->save( in, filename ) ) + return( -1 ); + + return( 0 ); +} diff --git a/libvips/include/vips/format.h b/libvips/include/vips/format.h index 9153293a..ccfa50c8 100644 --- a/libvips/include/vips/format.h +++ b/libvips/include/vips/format.h @@ -50,21 +50,14 @@ extern "C" { (G_TYPE_INSTANCE_GET_CLASS( (obj), \ VIPS_TYPE_FORMAT, VipsFormatClass )) -/* Image file properties. - */ -typedef enum { - VIPS_FORMAT_NONE = 0, /* No flags set */ - VIPS_FORMAT_PARTIAL = 1, /* Lazy read OK (eg. tiled tiff) */ - VIPS_FORMAT_BIGENDIAN = 2 /* Most-significant byte first */ -} VipsFormatFlags; - -/* Don't instantiate these things, just use the class stuff. - */ - typedef struct _VipsFormat { VipsObject parent_object; /*< public >*/ + /* Filename for load or save. + */ + char *filename; + } VipsFormat; typedef struct _VipsFormatClass { @@ -75,21 +68,9 @@ typedef struct _VipsFormatClass { */ gboolean (*is_a)( const char * ); - /* Read just the header into the VipsImage. + /* Null-terminated list of allowed suffixes, eg. ".tif", ".tiff". */ - int (*header)( const char *, VipsImage * ); - - /* Load the whole image. - */ - int (*load)( const char *, VipsImage * ); - - /* Write the VipsImage to the file in this format. - */ - int (*save)( VipsImage *, const char * ); - - /* Get the flags for this file in this format. - */ - VipsFormatFlags (*get_flags)( const char * ); + const char **suffs; /* Loop over formats in this order, default 0. We need this because * some formats can be read by several loaders (eg. tiff can be read @@ -98,9 +79,6 @@ typedef struct _VipsFormatClass { */ int priority; - /* Null-terminated list of allowed suffixes, eg. ".tif", ".tiff". - */ - const char **suffs; } VipsFormatClass; GType vips_format_get_type( void ); @@ -109,17 +87,117 @@ GType vips_format_get_type( void ); * subclasses of VipsFormat. */ void *vips_format_map( VipsSListMap2Fn fn, void *a, void *b ); -VipsFormatClass *vips_format_for_file( const char *filename ); -VipsFormatClass *vips_format_for_name( const char *filename ); + +#define VIPS_TYPE_FORMAT_LOAD (vips_format_load_get_type()) +#define VIPS_FORMAT_LOAD( obj ) \ + (G_TYPE_CHECK_INSTANCE_CAST( (obj), \ + VIPS_TYPE_FORMAT_LOAD, VipsFormatLoad )) +#define VIPS_FORMAT_LOAD_CLASS( klass ) \ + (G_TYPE_CHECK_CLASS_CAST( (klass), \ + VIPS_TYPE_FORMAT_LOAD, VipsFormatLoadClass)) +#define VIPS_IS_FORMAT_LOAD( obj ) \ + (G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_FORMAT_LOAD )) +#define VIPS_IS_FORMAT_LOAD_CLASS( klass ) \ + (G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_FORMAT_LOAD )) +#define VIPS_FORMAT_LOAD_GET_CLASS( obj ) \ + (G_TYPE_INSTANCE_GET_CLASS( (obj), \ + VIPS_TYPE_FORMAT_LOAD, VipsFormatLoadClass )) + +/* Image file properties. + */ +typedef enum { + VIPS_FORMAT_NONE = 0, /* No flags set */ + VIPS_FORMAT_PARTIAL = 1, /* Lazy read OK (eg. tiled tiff) */ + VIPS_FORMAT_BIGENDIAN = 2 /* Most-significant byte first */ +} VipsFormatFlags; + +typedef struct _VipsFormatLoad { + VipsFormat parent_object; + /*< public >*/ + + /* Flags read from the file. + */ + VipsFormatFlags flags; + + /* The image we've loaded. + */ + VipsImage *out; + +} VipsFormatLoad; + +typedef struct _VipsFormatLoadClass { + VipsFormatClass parent_class; + + /*< public >*/ + + /* Get the flags for this file in this format. + */ + VipsFormatFlags (*get_flags)( VipsFormatLoad * ); + + /* Load just the header. + */ + int (*header)( VipsFormatLoad * ); + + /* Load the whole image. + */ + int (*load)( VipsFormatLoad * ); + +} VipsFormatLoadClass; + +GType vips_format_load_get_type( void ); VipsFormatFlags vips_format_get_flags( VipsFormatClass *format, const char *filename ); +VipsFormatLoad *vips_format_for_file( const char *filename ); + +#define VIPS_TYPE_FORMAT_SAVE (vips_format_save_get_type()) +#define VIPS_FORMAT_SAVE( obj ) \ + (G_TYPE_CHECK_INSTANCE_CAST( (obj), \ + VIPS_TYPE_FORMAT_SAVE, VipsFormatSave )) +#define VIPS_FORMAT_SAVE_CLASS( klass ) \ + (G_TYPE_CHECK_CLASS_CAST( (klass), \ + VIPS_TYPE_FORMAT_SAVE, VipsFormatSaveClass)) +#define VIPS_IS_FORMAT_SAVE( obj ) \ + (G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_FORMAT_SAVE )) +#define VIPS_IS_FORMAT_SAVE_CLASS( klass ) \ + (G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_FORMAT_SAVE )) +#define VIPS_FORMAT_SAVE_GET_CLASS( obj ) \ + (G_TYPE_INSTANCE_GET_CLASS( (obj), \ + VIPS_TYPE_FORMAT_SAVE, VipsFormatSaveClass )) + +typedef struct _VipsFormatSave { + VipsFormat parent_object; + /*< public >*/ + +} VipsFormatSave; + +typedef struct _VipsFormatSaveClass { + VipsFormatClass parent_class; + + /*< public >*/ + + /* Write the VipsImage to the file in this format. + */ + int (*save)( VipsImage * ); + +} VipsFormatSaveClass; + +GType vips_format_save_get_type( void ); + +VipsFormatSave *vips_format_for_name( const char *filename ); + /* Read/write an image convenience functions. */ int vips_format_read( const char *filename, VipsImage *out ); int vips_format_write( VipsImage *in, const char *filename ); + + + + + + /* Low-level read/write operations. */ int im_jpeg2vips( const char *filename, VipsImage *out );