From 6c33ec9ff250b7a9e36b7000e59acbe03802641c Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 22 Dec 2011 12:12:27 +0000 Subject: [PATCH] foreign docs --- TODO | 2 +- doc/reference/libvips-docs.sgml.in | 2 +- libvips/foreign/foreign.c | 361 +++++++++++++++++------------ libvips/include/vips/foreign.h | 67 ++++-- libvips/iofuncs/image.c | 2 +- libvips/iofuncs/object.c | 8 +- 6 files changed, 269 insertions(+), 173 deletions(-) diff --git a/TODO b/TODO index f6ff981b..5d83d3f1 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -- foreign docs +- foreign docs come up as "VipsForeignSave", annoying, why? diff --git a/doc/reference/libvips-docs.sgml.in b/doc/reference/libvips-docs.sgml.in index 93cfaae1..68812a36 100644 --- a/doc/reference/libvips-docs.sgml.in +++ b/doc/reference/libvips-docs.sgml.in @@ -36,7 +36,7 @@ - + diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index c3d5ad79..55b7a84f 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -109,149 +109,210 @@ */ /** - * VipsForeign: + * VipsForeignClass: * - * #VipsForeign has these virtual methods: - * - * |[ - * typedef struct _VipsForeignClass { - * VipsObjectClass parent_class; - * - * gboolean (*is_a)( const char *filename ); - * int (*header)( const char *filename, VipsImage *out ); - * int (*load)( const char *filename, VipsImage *out ); - * int (*save)( VipsImage *in, const char *filename ); - * VipsForeignFlags (*get_flags)( const char *filename ); - * int priority; - * const char **suffs; - * } VipsForeignClass; - * ]| - * - * Add a new file to VIPS by subclassing VipsForeign. 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 - * file. - * 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 - * file. - * 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 file should fit in this - * list of - * supported files. 0 is a sensible value for most files. 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 file to save a file in, and to pick a + * 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 Foreign - * ]| - * - * To see a list of all the supported files. - * - * For example, the TIFF file is defined like this: - * -|[ -typedef VipsForeign VipsForeignTiff; -typedef VipsForeignClass VipsForeignTiffClass; - -static void -vips_foreign_tiff_class_init( VipsForeignTiffClass *class ) -{ - VipsObjectClass *object_class = (VipsObjectClass *) class; - VipsForeignClass *file_class = (VipsForeignClass *) class; - - object_class->nickname = "tiff"; - object_class->description = _( "TIFF" ); - - file_class->is_a = istiff; - file_class->header = tiff2vips_header; - file_class->load = im_tiff2vips; - file_class->save = im_vips2tiff; - file_class->get_flags = tiff_flags; - file_class->suffs = tiff_suffs; -} - -static void -vips_foreign_tiff_init( VipsForeignTiff *object ) -{ -} - -G_DEFINE_TYPE( VipsForeignTiff, vips_foreign_tiff, VIPS_TYPE_FOREIGN ); -]| - * - * Then call vips_foreign_tiff_get_type() somewhere in your init code to link - * the file into VIPS (though of course the tiff file is linked in for you - * already). * + * You should also define @nickname and @description in #VipsObject. */ -/* Abstract base class for image files. +/** + * VipsForeignLoad: + * + * @out must be set by @header(). @load(), if defined, must set @real. + */ + +/** + * VipsForeignLoadClass: + * + * Add a new loader to VIPS by subclassing #VipsForeignLoad. Subclasses need to + * implement at least @header(). + * + * As a complete example, here's the code for the PNG loader, minus the actual + * calls to libpng. + * + * |[ +typedef struct _VipsForeignLoadPng { + VipsForeignLoad parent_object; + + char *filename; +} VipsForeignLoadPng; + +typedef VipsForeignLoadClass VipsForeignLoadPngClass; + +G_DEFINE_TYPE( VipsForeignLoadPng, vips_foreign_load_png, + VIPS_TYPE_FOREIGN_LOAD ); + +static VipsForeignFlags +vips_foreign_load_png_get_flags_filename( const char *filename ) +{ + return( 0 ); +} + +static VipsForeignFlags +vips_foreign_load_png_get_flags( VipsForeignLoad *load ) +{ + VipsForeignLoadPng *png = (VipsForeignLoadPng *) load; + + return( vips_foreign_load_png_get_flags_filename( png->filename ) ); +} + +static int +vips_foreign_load_png_header( VipsForeignLoad *load ) +{ + VipsForeignLoadPng *png = (VipsForeignLoadPng *) load; + + if( vips__png_header( png->filename, load->out ) ) + return( -1 ); + + return( 0 ); +} + +static int +vips_foreign_load_png_load( VipsForeignLoad *load ) +{ + VipsForeignLoadPng *png = (VipsForeignLoadPng *) load; + + if( vips__png_read( png->filename, load->real ) ) + return( -1 ); + + return( 0 ); +} + +static void +vips_foreign_load_png_class_init( VipsForeignLoadPngClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignClass *foreign_class = (VipsForeignClass *) class; + VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + object_class->nickname = "pngload"; + object_class->description = _( "load png from file" ); + + foreign_class->suffs = vips__png_suffs; + + load_class->is_a = vips__png_ispng; + load_class->get_flags_filename = + vips_foreign_load_png_get_flags_filename; + load_class->get_flags = vips_foreign_load_png_get_flags; + load_class->header = vips_foreign_load_png_header; + load_class->load = vips_foreign_load_png_load; + + VIPS_ARG_STRING( class, "filename", 1, + _( "Filename" ), + _( "Filename to load from" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsForeignLoadPng, filename ), + NULL ); +} + +static void +vips_foreign_load_png_init( VipsForeignLoadPng *png ) +{ +} + * ]| + */ + +/** + * VipsForeignSaveClass: + * + * Call your saver in the class' @build() method after chaining up. The + * prepared image should be ready for you to save in @ready. + * + * As a complete example, here's the code for the CSV saver, minus the calls + * to the actual save routines. + * + * |[ +typedef struct _VipsForeignSaveCsv { + VipsForeignSave parent_object; + + char *filename; + const char *separator; +} VipsForeignSaveCsv; + +typedef VipsForeignSaveClass VipsForeignSaveCsvClass; + +G_DEFINE_TYPE( VipsForeignSaveCsv, vips_foreign_save_csv, + VIPS_TYPE_FOREIGN_SAVE ); + +static int +vips_foreign_save_csv_build( VipsObject *object ) +{ + VipsForeignSave *save = (VipsForeignSave *) object; + VipsForeignSaveCsv *csv = (VipsForeignSaveCsv *) object; + + if( VIPS_OBJECT_CLASS( vips_foreign_save_csv_parent_class )-> + build( object ) ) + return( -1 ); + + if( vips__csv_write( save->ready, csv->filename, csv->separator ) ) + return( -1 ); + + return( 0 ); +} + +#define UC VIPS_FORMAT_UCHAR +#define C VIPS_FORMAT_CHAR +#define US VIPS_FORMAT_USHORT +#define S VIPS_FORMAT_SHORT +#define UI VIPS_FORMAT_UINT +#define I VIPS_FORMAT_INT +#define F VIPS_FORMAT_FLOAT +#define X VIPS_FORMAT_COMPLEX +#define D VIPS_FORMAT_DOUBLE +#define DX VIPS_FORMAT_DPCOMPLEX + +static int bandfmt_csv[10] = { +// UC C US S UI I F X D DX + UC, C, US, S, UI, I, F, X, D, DX +}; + +static void +vips_foreign_save_csv_class_init( VipsForeignSaveCsvClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignClass *foreign_class = (VipsForeignClass *) class; + VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + object_class->nickname = "csvsave"; + object_class->description = _( "save image to csv file" ); + object_class->build = vips_foreign_save_csv_build; + + foreign_class->suffs = vips__foreign_csv_suffs; + + save_class->saveable = VIPS_SAVEABLE_MONO; + save_class->format_table = bandfmt_csv; + + VIPS_ARG_STRING( class, "filename", 1, + _( "Filename" ), + _( "Filename to save to" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsForeignSaveCsv, filename ), + NULL ); + + VIPS_ARG_STRING( class, "separator", 13, + _( "Separator" ), + _( "Separator characters" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsForeignSaveCsv, separator ), + "\t" ); +} + +static void +vips_foreign_save_csv_init( VipsForeignSaveCsv *csv ) +{ + csv->separator = g_strdup( "\t" ); +} + * ]| */ G_DEFINE_ABSTRACT_TYPE( VipsForeign, vips_foreign, VIPS_TYPE_OPERATION ); @@ -1115,7 +1176,7 @@ vips_foreign_save_init( VipsForeignSave *object ) } /** - * vips_foreign_read: + * vips_foreign_load: * @filename: file to load * @out: output image * @...: %NULL-terminated list of optional named arguments @@ -1123,12 +1184,12 @@ vips_foreign_save_init( VipsForeignSave *object ) * Loads @filename into @out using the loader recommended by * vips_foreign_find_load(). * - * See also: vips_foreign_write(), vips_foreign_read_options(). + * See also: vips_foreign_save(), vips_foreign_read_options(). * * Returns: 0 on success, -1 on error */ int -vips_foreign_read( const char *filename, VipsImage **out, ... ) +vips_foreign_load( const char *filename, VipsImage **out, ... ) { const char *operation; va_list ap; @@ -1145,7 +1206,7 @@ vips_foreign_read( const char *filename, VipsImage **out, ... ) } /** - * vips_foreign_write: + * vips_foreign_save: * @in: image to write * @filename: file to write to * @...: %NULL-terminated list of optional named arguments @@ -1153,12 +1214,12 @@ vips_foreign_read( const char *filename, VipsImage **out, ... ) * Saves @in to @filename using the saver recommended by * vips_foreign_find_save(). * - * See also: vips_foreign_read(). + * See also: vips_foreign_load(). * * Returns: 0 on success, -1 on error */ int -vips_foreign_write( VipsImage *in, const char *filename, ... ) +vips_foreign_save( VipsImage *in, const char *filename, ... ) { const char *operation; va_list ap; @@ -1175,7 +1236,7 @@ vips_foreign_write( VipsImage *in, const char *filename, ... ) } /** - * vips_foreign_read_options: + * vips_foreign_load_options: * @filename: file to load * @out: output image * @@ -1185,12 +1246,12 @@ vips_foreign_write( VipsImage *in, const char *filename, ... ) * Arguments to the loader may be embedded in the filename using the usual * syntax. * - * See also: vips_foreign_read(). + * See also: vips_foreign_load(). * * Returns: 0 on success, -1 on error */ int -vips_foreign_read_options( const char *filename, VipsImage **out ) +vips_foreign_load_options( const char *filename, VipsImage **out ) { VipsObjectClass *oclass = g_type_class_ref( VIPS_TYPE_FOREIGN_LOAD ); @@ -1226,19 +1287,19 @@ vips_foreign_read_options( const char *filename, VipsImage **out ) } /** - * vips_foreign_write_options: + * vips_foreign_save_options: * @in: image to write * @filename: file to write to * * Saves @in to @filename using the saver recommended by * vips_foreign_find_save(). * - * See also: vips_foreign_write(). + * See also: vips_foreign_save(). * * Returns: 0 on success, -1 on error */ int -vips_foreign_write_options( VipsImage *in, const char *filename ) +vips_foreign_save_options( VipsImage *in, const char *filename ) { VipsObjectClass *oclass = g_type_class_ref( VIPS_TYPE_FOREIGN_SAVE ); VipsObject *object; diff --git a/libvips/include/vips/foreign.h b/libvips/include/vips/foreign.h index 296c7de9..692b5113 100644 --- a/libvips/include/vips/foreign.h +++ b/libvips/include/vips/foreign.h @@ -52,6 +52,7 @@ extern "C" { typedef struct _VipsForeign { VipsOperation parent_object; + /*< public >*/ } VipsForeign; @@ -109,7 +110,7 @@ typedef enum { typedef struct _VipsForeignLoad { VipsForeign parent_object; - /*< public >*/ + /*< private >*/ /* Open to disc (default is to open to memory). */ @@ -119,12 +120,14 @@ typedef struct _VipsForeignLoad { */ VipsForeignFlags flags; - /* The image we generate. + /*< public >*/ + + /* The image we generate. This must be set by ->header(). */ VipsImage *out; /* The behind-the-scenes real image we decompress to. This can be a - * disc foreign or a memory buffer. + * disc foreign or a memory buffer. This must be set by ->load(). */ VipsImage *real; @@ -132,35 +135,55 @@ typedef struct _VipsForeignLoad { typedef struct _VipsForeignLoadClass { VipsForeignClass parent_class; - /*< public >*/ - /* Is a file in this format. + /* Is a file in this format. + * + * This function should return %TRUE if + * the file contains an image of this type. If you don't define this + * function, #VipsForeignLoad + * will use @suffs instead. */ gboolean (*is_a)( const char * ); - /* Get the flags for this image. - */ - VipsForeignFlags (*get_flags)( VipsForeignLoad * ); - - /* Get the flags from a filename. This is needed for vips7compat but - * newer loaders don't have to define it. + /* Get the flags from a filename. + * + * This function should examine the file and return a set + * of flags. If you don't define it, vips will default to 0 (no flags + * set). + * + * This operation is necessary for vips7 compatibility. */ VipsForeignFlags (*get_flags_filename)( const char * ); + /* Get the flags for this image. Images can be loaded from (for + * example) memory areas rather than files, so you can't just use + * @get_flags_filename(). + */ + VipsForeignFlags (*get_flags)( VipsForeignLoad * ); + /* 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 and only @header will be used. + * or if your loader does not support reading only the header, read + * the entire image in this method and leave @load() NULL. * - * ->header() needs to set the dhint on the image .. otherwise you get + * @header() needs to set the dhint on the image .. otherwise you get * the default SMALLTILE. + * + * Return 0 for success, -1 for error, setting + * vips_error(). */ int (*header)( VipsForeignLoad * ); /* Read the whole image into @real. It gets copied to @out later. + * + * You can omit this method if you define a @header() method which + * loads the while file. + * + * Return 0 for success, -1 for error, setting + * vips_error(). */ int (*load)( VipsForeignLoad * ); - } VipsForeignLoadClass; GType vips_foreign_load_get_type( void ); @@ -206,13 +229,17 @@ typedef enum { typedef struct _VipsForeignSave { VipsForeign parent_object; + /*< public >*/ - /* The image we are to save. + /* The image we are to save, as supplied by our caller. */ VipsImage *in; - /* The image converted to a saveable format (eg. 8-bit RGB). + /* @in converted to a saveable format (eg. 8-bit RGB) according to the + * instructions you give in the class fields below. + * + * This is the image you should actually write to the output. */ VipsImage *ready; @@ -224,10 +251,18 @@ typedef struct _VipsForeignSaveClass { /*< public >*/ /* How this format treats bands. + * + * @saveable describes the bands that your saver can handle. For + * example, PPM images can have 1 or 3 bands (mono or RGB), so it + * uses #VIPS_SAVEABLE_RGB. */ VipsSaveable saveable; /* How this format treats band formats. + * + * @format_table describes the band formats that your saver can + * handle. For each of the 10 #VipsBandFormat values, the array + * should give the format your saver will accept. */ VipsBandFormat *format_table; diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c index 9b819206..43235892 100644 --- a/libvips/iofuncs/image.c +++ b/libvips/iofuncs/image.c @@ -639,7 +639,7 @@ vips_image_build( VipsObject *object ) else { VipsImage *t; - if( vips_foreign_read_options( filename, &t ) ) + if( vips_foreign_load_options( filename, &t ) ) return( -1 ); image->dtype = VIPS_IMAGE_PARTIAL; diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index 6f275846..f41e6812 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -1303,10 +1303,10 @@ vips_object_set_argument_from_string( VipsObject *object, if( g_type_is_a( otype, VIPS_TYPE_IMAGE ) ) { VipsImage *out; - /* Read the filename. vips_foreign_read_options() + /* Read the filename. vips_foreign_load_options() * handles embedded options. */ - if( vips_foreign_read_options( value, &out ) ) + if( vips_foreign_load_options( value, &out ) ) return( -1 ); g_value_init( &gvalue, VIPS_TYPE_IMAGE ); @@ -1478,10 +1478,10 @@ vips_object_get_argument_to_string( VipsObject *object, VipsImage *in; /* Pull out the image and write it. - * vips_foreign_write_options() handles embedded options. + * vips_foreign_save_options() handles embedded options. */ g_object_get( object, name, &in, NULL ); - if( vips_foreign_write_options( in, arg ) ) { + if( vips_foreign_save_options( in, arg ) ) { g_object_unref( in ); return( -1 ); }