more docs work
This commit is contained in:
parent
ce428ffa94
commit
2f72a9925f
@ -1,3 +1,6 @@
|
||||
12/8/14 started 7.40.5
|
||||
- more doc fixes
|
||||
|
||||
25/7/14 started 7.40.5
|
||||
- fix a race in im_maxpos_avg()
|
||||
- limit n_thr on tiny images
|
||||
|
7
TODO
7
TODO
@ -1,12 +1,15 @@
|
||||
- can we pick the vipsthumbnail int shrink factor more intelligently?
|
||||
|
||||
- did we include the exif patch in the latest windows build? check on laptop
|
||||
|
||||
we don't seem to have this fix in the repository!
|
||||
|
||||
- vips_object_unref_outputs() needs docs ... bindings will need it
|
||||
|
||||
- copy-paste blog post about writing vips8 operations into 'extending'
|
||||
|
||||
- vips_init() has a deprecation warning, bizarre
|
||||
|
||||
|
||||
|
||||
- check and fix up docs
|
||||
|
||||
index items should all be links
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
# also update the version number in the m4 macros below
|
||||
|
||||
AC_INIT([vips], [7.40.5], [vipsip@jiscmail.ac.uk])
|
||||
AC_INIT([vips], [7.40.6], [vipsip@jiscmail.ac.uk])
|
||||
# required for gobject-introspection
|
||||
AC_PREREQ(2.62)
|
||||
|
||||
@ -18,7 +18,7 @@ AC_CONFIG_MACRO_DIR([m4])
|
||||
# user-visible library versioning
|
||||
m4_define([vips_major_version], [7])
|
||||
m4_define([vips_minor_version], [40])
|
||||
m4_define([vips_micro_version], [5])
|
||||
m4_define([vips_micro_version], [6])
|
||||
m4_define([vips_version],
|
||||
[vips_major_version.vips_minor_version.vips_micro_version])
|
||||
|
||||
@ -38,7 +38,7 @@ VIPS_VERSION_STRING=$VIPS_VERSION-`date`
|
||||
# binary interface changes not backwards compatible?: reset age to 0
|
||||
|
||||
LIBRARY_CURRENT=38
|
||||
LIBRARY_REVISION=3
|
||||
LIBRARY_REVISION=4
|
||||
LIBRARY_AGE=0
|
||||
|
||||
# patched into include/vips/version.h
|
||||
|
@ -19,6 +19,18 @@
|
||||
<para>
|
||||
Write this section once the vips8 Python binding is done.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If you are writing a language binding, you won't need these. Instead, make
|
||||
a new operation with vips_operation_new() (all it does is look up the
|
||||
operation by name with vips_type_find(), then call g_object_new() for you),
|
||||
then use vips_argument_map() and friends to loop over the operation's
|
||||
arguments setting them. Once you have set all arguments, use
|
||||
vips_cache_operation_build() to look up the operation in the cache and
|
||||
either build or dup it. If something goes wrong, you'll need to use
|
||||
vips_object_unref_outputs() and g_object_unref() to free the
|
||||
partially-built object.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
|
@ -14,23 +14,354 @@
|
||||
<refpurpose>How to add operations to VIPS</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsect1 id="extending-subclassing">
|
||||
<title>Adding operations to VIPS</title>
|
||||
<refsect1 id="extending-pointtopoint">
|
||||
<title>A simple point-to-point operation</title>
|
||||
|
||||
<para>
|
||||
All about subclassing. Copy-paste from the blog post about extending
|
||||
vips8.
|
||||
All operations are subclasses of #VipsOperation, which in turn
|
||||
subclasses #VipsObject and then %GObject. You need to define a new
|
||||
instance struct and a new class struct.
|
||||
|
||||
<programlisting language="C">
|
||||
typedef struct _Negative {
|
||||
VipsOperation parent_instance;
|
||||
|
||||
VipsImage *in;
|
||||
VipsImage *out;
|
||||
|
||||
int image_max;
|
||||
|
||||
} Negative;
|
||||
|
||||
typedef struct _NegativeClass {
|
||||
VipsOperationClass parent_class;
|
||||
|
||||
/* No new class members needed for this op.
|
||||
*/
|
||||
|
||||
} NegativeClass;
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If you are writing a language binding, you won't need these. Instead, make
|
||||
a new operation with vips_operation_new() (all it does is look up the
|
||||
operation by name with vips_type_find(), then call g_object_new() for you),
|
||||
then use vips_argument_map() and friends to loop over the operation's
|
||||
arguments setting them. Once you have set all arguments, use
|
||||
vips_cache_operation_build() to look up the operation in the cache and
|
||||
either build or dup it. If something goes wrong, you'll need to use
|
||||
vips_object_unref_outputs() and g_object_unref() to free the
|
||||
partially-built object.
|
||||
This operation will find the photographic negative of an unsigned
|
||||
8-bit image, optionally letting you specify the value which the pixels
|
||||
"pivot" about. It doesn't need any class members (ie. values common
|
||||
to all operations of this type), so the second struct is empty. See
|
||||
vips_invert() for a more complete version of this operation that's
|
||||
actually in the library.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
GObject has a handy macro to write some of the boilerplate for you.
|
||||
|
||||
<programlisting language="C">
|
||||
G_DEFINE_TYPE( Negative, negative, VIPS_TYPE_OPERATION );
|
||||
</programlisting>
|
||||
|
||||
This defines a function called negative_get_type(),
|
||||
which registers this new class and returns its #GType (a
|
||||
pointer-sized integer). negative_get_type() in turn needs two
|
||||
functions, negative_init(), to initialise a new instance, and
|
||||
negative_class_init(), to initialise a new class.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
negative_init() is very simple, it just sets the default value for
|
||||
our optional class parameter.
|
||||
|
||||
<programlisting language="C">
|
||||
static void
|
||||
negative_init( Negative *negative )
|
||||
{
|
||||
negative->image_max = 255;
|
||||
}
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
negative_class_init() is more complicated: it has to set various
|
||||
fields in various superclasses.
|
||||
|
||||
<programlisting language="C">
|
||||
static void
|
||||
negative_class_init( NegativeClass *class )
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( class );
|
||||
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
object_class->nickname = "negative";
|
||||
object_class->description = "photographic negative";
|
||||
object_class->build = negative_build;
|
||||
|
||||
VIPS_ARG_IMAGE( class, "in", 1,
|
||||
"Input",
|
||||
"Input image",
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
G_STRUCT_OFFSET( Negative, in ) );
|
||||
|
||||
VIPS_ARG_IMAGE( class, "out", 2,
|
||||
"Output",
|
||||
"Output image",
|
||||
VIPS_ARGUMENT_REQUIRED_OUTPUT,
|
||||
G_STRUCT_OFFSET( Negative, out ) );
|
||||
|
||||
VIPS_ARG_INT( class, "image_max", 4,
|
||||
"Image maximum",
|
||||
"Maximum value in image: pivot about this",
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( Negative, image_max ),
|
||||
0, 255, 255 );
|
||||
}
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In %GObject, it needs to set the getters and setters for this class. vips
|
||||
has a generic get/set system, so any subclass of #VipsObject needs to
|
||||
use the vips ones.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In #VipsObject, it needs to set the operation @nickname and @description,
|
||||
and set a build function (see below). @nickname is used to refer to
|
||||
this operation in the API, @description is used to explain this
|
||||
operation to users and will be translated into their language.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Finally, it needs to set the arguments this class constructor
|
||||
takes. There are a set of handy macros for doing this. The first few
|
||||
parameters are always the same and mean: class pointer for argument,
|
||||
argument name, argument priority (bindings expect required arguments in
|
||||
order of priority), long argument name (this one is internationalised
|
||||
and displayed to users), description (again, users can see this),
|
||||
some flags describing the argument, and finally the position of the
|
||||
member in the struct.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Integer arguments take three more values: the minimum, maximum and
|
||||
default value for the argument.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The build function is the thing VipsObject calls after supplying
|
||||
arguments. It checks that all required arguments have been set and are
|
||||
valid and constructs the object. After build, the object is expected
|
||||
to be ready for use.
|
||||
|
||||
<programlisting language="C">
|
||||
static int
|
||||
negative_build( VipsObject *object )
|
||||
{
|
||||
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
|
||||
Negative *negative = (Negative *) object;
|
||||
|
||||
if( VIPS_OBJECT_CLASS( negative_parent_class )->build( object ) )
|
||||
return( -1 );
|
||||
|
||||
if( vips_check_uncoded( class->nickname, negative->in ) ||
|
||||
vips_check_format( class->nickname, negative->in, VIPS_FORMAT_UCHAR ) )
|
||||
return( -1 );
|
||||
|
||||
g_object_set( object, "out", vips_image_new(), NULL );
|
||||
|
||||
if( vips_image_pipelinev( negative->out,
|
||||
VIPS_DEMAND_STYLE_THINSTRIP, negative->in, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
if( vips_image_generate( negative->out,
|
||||
vips_start_one,
|
||||
negative_generate,
|
||||
vips_stop_one,
|
||||
negative->in, negative ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
negative_build() first chains up to the superclass: this will check
|
||||
that all input arguments have been supplied and are sane.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Next, it adds its own checks. This is a demo operation, so we just
|
||||
work for uncoded, unsigned 8-bit images.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Next, it creates the output image. This needs to be set with
|
||||
g_object_set() so that vips can see that it has been assigned. vips
|
||||
will also handle the reference counting for you.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
vips_image_pipelinev() links our new image onto the input image and
|
||||
notes that this operation prefers to work in lines.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Finally, vips_image_generate() attaches a set of callbacks to the
|
||||
output image to generate chunks of it on request. vips_start_one()
|
||||
and vips_stop_one() are convenience functions that make the input
|
||||
region for you.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
And then the actual image processing.
|
||||
|
||||
<programlisting language="C">
|
||||
static int
|
||||
negative_generate( VipsRegion *or,
|
||||
void *vseq, void *a, void *b, gboolean *stop )
|
||||
{
|
||||
/* The area of the output region we have been asked to make.
|
||||
*/
|
||||
VipsRect *r = &or->valid;
|
||||
|
||||
/* The sequence value ... the thing returned by vips_start_one().
|
||||
*/
|
||||
VipsRegion *ir = (VipsRegion *) vseq;
|
||||
|
||||
Negative *negative = (Negative *) b;
|
||||
int line_size = r->width * negative->in->Bands;
|
||||
|
||||
int x, y;
|
||||
|
||||
/* Request matching part of input region.
|
||||
*/
|
||||
if( vips_region_prepare( ir, r ) )
|
||||
return( -1 );
|
||||
|
||||
for( y = 0; y < r->height; y++ ) {
|
||||
unsigned char *p = (unsigned char *)
|
||||
VIPS_REGION_ADDR( ir, r->left, r->top + y );
|
||||
unsigned char *q = (unsigned char *)
|
||||
VIPS_REGION_ADDR( or, r->left, r->top + y );
|
||||
|
||||
for( x = 0; x < line_size; x++ )
|
||||
q[x] = negative->image_max - p[x];
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This has to calculate a section of the output image. The output
|
||||
#VipsRegion, @or, contains a #VipsRect called @valid which is the
|
||||
area needing calculation. negative_generate() asks for the
|
||||
corresponding pixels from the input region, then loops over the
|
||||
area. VIPS_REGION_ADDR() is a simple macro that does pointer arithmetic
|
||||
for you: you need to stay within the valid area.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To add the operation to vips, just call negative_get_type(). You
|
||||
can then use @negative from any of the vips interfaces. For example,
|
||||
in Python you'd use it like this:
|
||||
|
||||
<programlisting language="python">
|
||||
out = in.negative(image_max = 128)
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
From the command-line it'd look like this:
|
||||
|
||||
<programlisting language="bash">
|
||||
$ vips negative in.png out.tif --image-max 128
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
And from C like this:
|
||||
|
||||
<programlisting language="C">
|
||||
VipsImage *in;
|
||||
VipsImage *out;
|
||||
if( vips_call( "negative", in, &out, "image_max", 128, NULL ) )
|
||||
... error
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Unfortunately that will do almost no compile-time type checking,
|
||||
so all vips operations have a tiny extra wrapper to add a bit of
|
||||
safety. For example:
|
||||
|
||||
<programlisting language="C">
|
||||
static int
|
||||
negative( VipsImage *in, VipsImage **out, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_start( ap, out );
|
||||
result = vips_call_split( "negative", ap, in, out );
|
||||
va_end( ap );
|
||||
|
||||
return( result );
|
||||
}
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
And now you can write:
|
||||
|
||||
<programlisting language="C">
|
||||
if( negative( in, &out, "image_max", 128, NULL ) )
|
||||
... error
|
||||
</programlisting>
|
||||
|
||||
and it's at least a bit safer.
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="extending-othertypes">
|
||||
<title>Other types of operation</title>
|
||||
<para>
|
||||
Change the _build() function to make other types of operation.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Use vips_image_generate() with vips_start_many() to make operations
|
||||
which demand pixels from more than one image at once, such as image
|
||||
plus image.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Use vips_sink() instead of vips_image_generate() to loop over an image
|
||||
and calculate a value. vips uses this for the statistics operations,
|
||||
like vips_avg().
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Use vips_image_wio_input() to get an entire image into memory so you
|
||||
can read it with a pointer. This will obviously not scale well to
|
||||
very large images, but some operations, like FFTs or flood-fill, need
|
||||
the whole image to be available at once.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Make area operations, like filters, by enlarging the #VipsRect that
|
||||
_generate() is given before calling vips_image_prepare(). You can
|
||||
enlarge the input image, so that the output image is the same size as
|
||||
the original input, by using vips_embed() within the _build() function.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Make things like flips and rotates by making larger changes to the
|
||||
#VipsRect in _generate().
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
|
Loading…
Reference in New Issue
Block a user