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 );
}