rework binding docs
This commit is contained in:
parent
0aecd57513
commit
6397aae326
@ -148,6 +148,7 @@ markdown_content_files = \
|
|||||||
How-it-opens-files.md \
|
How-it-opens-files.md \
|
||||||
Examples.md \
|
Examples.md \
|
||||||
Cite.md \
|
Cite.md \
|
||||||
|
binding.md \
|
||||||
Making-image-pyramids.md
|
Making-image-pyramids.md
|
||||||
|
|
||||||
# converted to xml in this dir by pandoc
|
# converted to xml in this dir by pandoc
|
||||||
@ -159,13 +160,11 @@ content_files = \
|
|||||||
using-command-line.xml \
|
using-command-line.xml \
|
||||||
using-C.xml \
|
using-C.xml \
|
||||||
using-threads.xml \
|
using-threads.xml \
|
||||||
using-python.xml \
|
|
||||||
using-cpp.xml \
|
using-cpp.xml \
|
||||||
extending.xml \
|
extending.xml \
|
||||||
function-list.xml \
|
function-list.xml \
|
||||||
file-format.xml \
|
file-format.xml \
|
||||||
${markdown_content_files_docbook} \
|
${markdown_content_files_docbook}
|
||||||
binding.xml
|
|
||||||
|
|
||||||
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
|
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
|
||||||
# These files must be listed here *and* in content_files
|
# These files must be listed here *and* in content_files
|
||||||
@ -174,13 +173,11 @@ expand_content_files = \
|
|||||||
using-command-line.xml \
|
using-command-line.xml \
|
||||||
using-C.xml \
|
using-C.xml \
|
||||||
using-threads.xml \
|
using-threads.xml \
|
||||||
using-python.xml \
|
|
||||||
using-cpp.xml \
|
using-cpp.xml \
|
||||||
extending.xml \
|
extending.xml \
|
||||||
function-list.xml \
|
function-list.xml \
|
||||||
file-format.xml \
|
file-format.xml \
|
||||||
${markdown_content_files_docbook} \
|
${markdown_content_files_docbook}
|
||||||
binding.xml
|
|
||||||
|
|
||||||
# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
|
# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
|
||||||
# Only needed if you are using gtkdoc-scangobj to dynamically query widget
|
# Only needed if you are using gtkdoc-scangobj to dynamically query widget
|
||||||
|
223
doc/binding.md
Normal file
223
doc/binding.md
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
<refmeta>
|
||||||
|
<refentrytitle>How to write bindings</refentrytitle>
|
||||||
|
<manvolnum>3</manvolnum>
|
||||||
|
<refmiscinfo>libvips</refmiscinfo>
|
||||||
|
</refmeta>
|
||||||
|
|
||||||
|
<refnamediv>
|
||||||
|
<refname>Binding</refname>
|
||||||
|
<refpurpose>Writing bindings for libvips</refpurpose>
|
||||||
|
</refnamediv>
|
||||||
|
|
||||||
|
There are full libvips bindings for quite a few languages now: C, C++, Ruby,
|
||||||
|
PHP, Python and JavaScript.
|
||||||
|
|
||||||
|
This chapter runs through the four main styles that have been found to work
|
||||||
|
well. If you want to write a new binding, one of these should be close
|
||||||
|
to what you need.
|
||||||
|
|
||||||
|
# C API
|
||||||
|
|
||||||
|
The libvips C API (vips_add() and so on) is very inconvenient to use from other
|
||||||
|
languages due to its heavy use of varargs.
|
||||||
|
|
||||||
|
It's much better to use the layer below. This lower layer is structured as:
|
||||||
|
create operator, set parameters, execute, extract results. For example, you can
|
||||||
|
execute vips_invert() like this:
|
||||||
|
|
||||||
|
```C
|
||||||
|
/* compile with
|
||||||
|
*
|
||||||
|
* gcc -g -Wall callvips.c `pkg-config vips --cflags --libs`
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <vips/vips.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main( int argc, char **argv )
|
||||||
|
{
|
||||||
|
VipsImage *in;
|
||||||
|
VipsImage *out;
|
||||||
|
VipsOperation *op;
|
||||||
|
VipsOperation *new_op;
|
||||||
|
GValue gvalue = { 0 };
|
||||||
|
|
||||||
|
if( VIPS_INIT( argv[0] ) )
|
||||||
|
/* This shows the vips error buffer and quits with a fail exit
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
vips_error_exit( NULL );
|
||||||
|
|
||||||
|
/* This will print a table of any ref leaks on exit, very handy for
|
||||||
|
* development.
|
||||||
|
*/
|
||||||
|
vips_leak_set( TRUE );
|
||||||
|
|
||||||
|
if( argc != 3 )
|
||||||
|
vips_error_exit( "usage: %s input-filename output-filename",
|
||||||
|
argv[0] );
|
||||||
|
|
||||||
|
if( !(in = vips_image_new_from_file( argv[1], NULL )) )
|
||||||
|
vips_error_exit( NULL );
|
||||||
|
|
||||||
|
/* Create a new operator from a nickname. NULL for unknown operator.
|
||||||
|
*/
|
||||||
|
op = vips_operation_new( "invert" );
|
||||||
|
|
||||||
|
/* Init a gvalue as an image, set it to in, use the gvalue to set the
|
||||||
|
* operator property.
|
||||||
|
*/
|
||||||
|
g_value_init( &gvalue, VIPS_TYPE_IMAGE );
|
||||||
|
g_value_set_object( &gvalue, in );
|
||||||
|
g_object_set_property( G_OBJECT( op ), "in", &gvalue );
|
||||||
|
g_value_unset( &gvalue );
|
||||||
|
|
||||||
|
/* We no longer need in: op will hold a ref to it as long as it needs
|
||||||
|
* it.
|
||||||
|
*/
|
||||||
|
g_object_unref( in );
|
||||||
|
|
||||||
|
/* Call the operation. This will look up the operation+args in the vips
|
||||||
|
* operation cache and either return a previous operation, or build
|
||||||
|
* this one. In either case, we have a new ref we mst release.
|
||||||
|
*/
|
||||||
|
if( !(new_op = vips_cache_operation_build( op )) ) {
|
||||||
|
g_object_unref( op );
|
||||||
|
vips_error_exit( NULL );
|
||||||
|
}
|
||||||
|
g_object_unref( op );
|
||||||
|
op = new_op;
|
||||||
|
|
||||||
|
/* Now get the result from op. g_value_get_object() does not ref the
|
||||||
|
* object, so we need to make a ref for out to hold.
|
||||||
|
*/
|
||||||
|
g_value_init( &gvalue, VIPS_TYPE_IMAGE );
|
||||||
|
g_object_get_property( G_OBJECT( op ), "out", &gvalue );
|
||||||
|
out = VIPS_IMAGE( g_value_get_object( &gvalue ) );
|
||||||
|
g_object_ref( out );
|
||||||
|
g_value_unset( &gvalue );
|
||||||
|
|
||||||
|
/* All done: we can unref op. The output objects from op actually hold
|
||||||
|
* refs back to it, so before we can unref op, we must unref them.
|
||||||
|
*/
|
||||||
|
vips_object_unref_outputs( VIPS_OBJECT( op ) );
|
||||||
|
g_object_unref( op );
|
||||||
|
|
||||||
|
if( vips_image_write_to_file( out, argv[2], NULL ) )
|
||||||
|
vips_error_exit( NULL );
|
||||||
|
|
||||||
|
g_object_unref( out );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
libvips has a couple of extra things to let you fetch the arguments and types
|
||||||
|
of an operator. Use vips_lib.vips_argument_map() to loop over all the arguments
|
||||||
|
of an operator, and vips_object_get_argument() to fetch the type and flags
|
||||||
|
of a specific argument.
|
||||||
|
|
||||||
|
Use vips_operation_get_flags() to get general information about an operator.
|
||||||
|
|
||||||
|
# Compiled language which can call C
|
||||||
|
|
||||||
|
The C++ binding uses this lower layer to define a function called
|
||||||
|
`VImage::call()` which can call any libvips operator with a not-varargs set of
|
||||||
|
variable arguments.
|
||||||
|
|
||||||
|
A small Python program walks the set of all libvips operators and generates a
|
||||||
|
set of static bindings. For example:
|
||||||
|
|
||||||
|
```c++
|
||||||
|
VImage VImage::invert( VOption *options )
|
||||||
|
{
|
||||||
|
VImage out;
|
||||||
|
|
||||||
|
call( "invert", (options ? options : VImage::option()) ->
|
||||||
|
set( "in", *this ) ->
|
||||||
|
set( "out", &out ) );
|
||||||
|
|
||||||
|
return( out );
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
So from C++ you can call any libvips operator, though without type-safety, with
|
||||||
|
`VImage::call()`, or use the member functions on `VImage` to get type-safe
|
||||||
|
calls for at least the required operator arguments.
|
||||||
|
|
||||||
|
The `VImage` class also adds automatic reference counting, constant expansion,
|
||||||
|
operator overloads, and various other useful features.
|
||||||
|
|
||||||
|
# Dynamic language with FFI
|
||||||
|
|
||||||
|
Languages like Ruby, Python, JavaScript and Lua can't call C directly, but
|
||||||
|
they do support FFI. The bindings for these languages work rather like C++,
|
||||||
|
but use FFI to call into libvips and run operations.
|
||||||
|
|
||||||
|
Since these languages are dynamic, they can add another trick: they intercept
|
||||||
|
the method-missing hook and attempt to run any method calls not implemented by
|
||||||
|
the `Image` class as libvips operators. This makes these bindings self-writing:
|
||||||
|
they only contain a small amount of codeand just expose everything they find in
|
||||||
|
the libvips class hierarchy.
|
||||||
|
|
||||||
|
# Dynamic langauge without FFI
|
||||||
|
|
||||||
|
PHP does not have FFI, unfortunately, so for this language a small native
|
||||||
|
module implements the general `vips_call()` function for PHP language types,
|
||||||
|
and a larger pure PHP layer makes it convenient to use.
|
||||||
|
|
||||||
|
# `gobject-introspection`
|
||||||
|
|
||||||
|
The C source code to libvips has been marked up with special comments
|
||||||
|
describing the interface in a standard way. These comments are read by
|
||||||
|
the `gobject-introspection` package when libvips is compiled and used to
|
||||||
|
generate a typelib, a description of how to call the library. Many languages
|
||||||
|
have gobject-introspection packages: all you need to do to call libvips
|
||||||
|
from your favorite language is to start g-o-i, load the libvips typelib,
|
||||||
|
and you should have the whole library available. For example, from Python
|
||||||
|
it's as simple as:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from gi.repository import Vips
|
||||||
|
```
|
||||||
|
|
||||||
|
libvips used in this way is likely to be rather bare-bones. For Python, we
|
||||||
|
wrote a set of overrides which layer a more Pythonesque interface on top
|
||||||
|
of the one provided for libvips by pygobject. These overrides are simply
|
||||||
|
a set of Python classes.
|
||||||
|
|
||||||
|
To call a vips operation, you'll need to 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. The Python binding uses
|
||||||
|
this technique to implement a function which can call any vips operation,
|
||||||
|
turning optional vips arguments into Python keyword arguments.
|
||||||
|
|
||||||
|
You can generate searchable docs from a <code>.gir</code> (the thing that
|
||||||
|
is built from scanning libvips and which in turn turn the typelib is
|
||||||
|
made from) with <command>g-ir-doc-tool</command>, for example:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ g-ir-doc-tool --language=Python -o ~/mydocs Vips-8.0.gir
|
||||||
|
```
|
||||||
|
|
||||||
|
Then to view them, either:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ yelp ~/mydocs
|
||||||
|
```
|
||||||
|
|
||||||
|
Or perhaps:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cd ~/mydocs
|
||||||
|
$ yelp-build html .
|
||||||
|
```
|
||||||
|
|
||||||
|
To make HTML docs. This is an easy way to see what you can call in the
|
||||||
|
library.
|
266
doc/binding.xml
266
doc/binding.xml
@ -1,94 +1,202 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
<!-- vim: set ts=2 sw=2 expandtab: -->
|
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
<refentry id="binding.md">
|
||||||
]>
|
|
||||||
<refentry id="binding">
|
|
||||||
<refmeta>
|
|
||||||
<refentrytitle>Writing bindings for libvips</refentrytitle>
|
|
||||||
<manvolnum>3</manvolnum>
|
|
||||||
<refmiscinfo>VIPS Library</refmiscinfo>
|
|
||||||
</refmeta>
|
|
||||||
|
|
||||||
<refnamediv>
|
|
||||||
<refname>Binding</refname>
|
|
||||||
<refpurpose>How to write bindings for libvips</refpurpose>
|
|
||||||
</refnamediv>
|
|
||||||
|
|
||||||
<refsect3 id="binding-goi">
|
<para>
|
||||||
<title>Binding and gobject-introspection</title>
|
<refmeta> <refentrytitle>How to write bindings</refentrytitle> <manvolnum>3</manvolnum> <refmiscinfo>libvips</refmiscinfo> </refmeta>
|
||||||
<para>
|
</para>
|
||||||
The C source code
|
<para>
|
||||||
to libvips has been marked up with special comments describing the
|
<refnamediv> <refname>Binding</refname> <refpurpose>Writing bindings for libvips</refpurpose> </refnamediv>
|
||||||
interface in a standard way. These comments are read by
|
</para>
|
||||||
gobject-introspection
|
<para>
|
||||||
when libvips is compiled and used to generate a
|
There are full libvips bindings for quite a few languages now: C, C++, Ruby, PHP, Python and JavaScript.
|
||||||
typelib, a description of how to call the library. Many languages have
|
</para>
|
||||||
gobject-introspection packages: all you need to do to call libvips
|
<para>
|
||||||
from your favorite language is to start g-o-i, load the libvips typelib,
|
This chapter runs through the four main styles that have been found to work well. If you want to write a new binding, one of these should be close to what you need.
|
||||||
and you should have the whole library available. For example, from
|
</para>
|
||||||
Python it's as simple as:
|
<refsect3 id="c-api">
|
||||||
|
<title>C API</title>
|
||||||
|
<para>
|
||||||
|
The libvips C API (vips_add() and so on) is very inconvenient to use from other languages due to its heavy use of varargs.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
It’s much better to use the layer below. This lower layer is structured as: create operator, set parameters, execute, extract results. For example, you can execute vips_invert() like this:
|
||||||
|
</para>
|
||||||
|
<programlisting language="c">
|
||||||
|
/* compile with
|
||||||
|
*
|
||||||
|
* gcc -g -Wall callvips.c `pkg-config vips --cflags --libs`
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
<programlisting language="Python">
|
#include <vips/vips.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main( int argc, char **argv )
|
||||||
|
{
|
||||||
|
VipsImage *in;
|
||||||
|
VipsImage *out;
|
||||||
|
VipsOperation *op;
|
||||||
|
VipsOperation *new_op;
|
||||||
|
GValue gvalue = { 0 };
|
||||||
|
|
||||||
|
if( VIPS_INIT( argv[0] ) )
|
||||||
|
/* This shows the vips error buffer and quits with a fail exit
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
vips_error_exit( NULL );
|
||||||
|
|
||||||
|
/* This will print a table of any ref leaks on exit, very handy for
|
||||||
|
* development.
|
||||||
|
*/
|
||||||
|
vips_leak_set( TRUE );
|
||||||
|
|
||||||
|
if( argc != 3 )
|
||||||
|
vips_error_exit( "usage: %s input-filename output-filename",
|
||||||
|
argv[0] );
|
||||||
|
|
||||||
|
if( !(in = vips_image_new_from_file( argv[1], NULL )) )
|
||||||
|
vips_error_exit( NULL );
|
||||||
|
|
||||||
|
/* Create a new operator from a nickname. NULL for unknown operator.
|
||||||
|
*/
|
||||||
|
op = vips_operation_new( "invert" );
|
||||||
|
|
||||||
|
/* Init a gvalue as an image, set it to in, use the gvalue to set the
|
||||||
|
* operator property.
|
||||||
|
*/
|
||||||
|
g_value_init( &gvalue, VIPS_TYPE_IMAGE );
|
||||||
|
g_value_set_object( &gvalue, in );
|
||||||
|
g_object_set_property( G_OBJECT( op ), "in", &gvalue );
|
||||||
|
g_value_unset( &gvalue );
|
||||||
|
|
||||||
|
/* We no longer need in: op will hold a ref to it as long as it needs
|
||||||
|
* it.
|
||||||
|
*/
|
||||||
|
g_object_unref( in );
|
||||||
|
|
||||||
|
/* Call the operation. This will look up the operation+args in the vips
|
||||||
|
* operation cache and either return a previous operation, or build
|
||||||
|
* this one. In either case, we have a new ref we mst release.
|
||||||
|
*/
|
||||||
|
if( !(new_op = vips_cache_operation_build( op )) ) {
|
||||||
|
g_object_unref( op );
|
||||||
|
vips_error_exit( NULL );
|
||||||
|
}
|
||||||
|
g_object_unref( op );
|
||||||
|
op = new_op;
|
||||||
|
|
||||||
|
/* Now get the result from op. g_value_get_object() does not ref the
|
||||||
|
* object, so we need to make a ref for out to hold.
|
||||||
|
*/
|
||||||
|
g_value_init( &gvalue, VIPS_TYPE_IMAGE );
|
||||||
|
g_object_get_property( G_OBJECT( op ), "out", &gvalue );
|
||||||
|
out = VIPS_IMAGE( g_value_get_object( &gvalue ) );
|
||||||
|
g_object_ref( out );
|
||||||
|
g_value_unset( &gvalue );
|
||||||
|
|
||||||
|
/* All done: we can unref op. The output objects from op actually hold
|
||||||
|
* refs back to it, so before we can unref op, we must unref them.
|
||||||
|
*/
|
||||||
|
vips_object_unref_outputs( VIPS_OBJECT( op ) );
|
||||||
|
g_object_unref( op );
|
||||||
|
|
||||||
|
if( vips_image_write_to_file( out, argv[2], NULL ) )
|
||||||
|
vips_error_exit( NULL );
|
||||||
|
|
||||||
|
g_object_unref( out );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
libvips has a couple of extra things to let you fetch the arguments and types of an operator. Use vips_lib.vips_argument_map() to loop over all the arguments of an operator, and vips_object_get_argument() to fetch the type and flags of a specific argument.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Use vips_operation_get_flags() to get general information about an operator.
|
||||||
|
</para>
|
||||||
|
</refsect3>
|
||||||
|
<refsect3 id="compiled-language-which-can-call-c">
|
||||||
|
<title>Compiled language which can call C</title>
|
||||||
|
<para>
|
||||||
|
The C++ binding uses this lower layer to define a function called <literal>VImage::call()</literal> which can call any libvips operator with a not-varargs set of variable arguments.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
A small Python program walks the set of all libvips operators and generates a set of static bindings. For example:
|
||||||
|
</para>
|
||||||
|
<programlisting language="cpp">
|
||||||
|
VImage VImage::invert( VOption *options )
|
||||||
|
{
|
||||||
|
VImage out;
|
||||||
|
|
||||||
|
call( "invert", (options ? options : VImage::option()) ->
|
||||||
|
set( "in", *this ) ->
|
||||||
|
set( "out", &out ) );
|
||||||
|
|
||||||
|
return( out );
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
So from C++ you can call any libvips operator, though without type-safety, with <literal>VImage::call()</literal>, or use the member functions on <literal>VImage</literal> to get type-safe calls for at least the required operator arguments.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The <literal>VImage</literal> class also adds automatic reference counting, constant expansion, operator overloads, and various other useful features.
|
||||||
|
</para>
|
||||||
|
</refsect3>
|
||||||
|
<refsect3 id="dynamic-language-with-ffi">
|
||||||
|
<title>Dynamic language with FFI</title>
|
||||||
|
<para>
|
||||||
|
Languages like Ruby, Python, JavaScript and Lua can’t call C directly, but they do support FFI. The bindings for these languages work rather like C++, but use FFI to call into libvips and run operations.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Since these languages are dynamic, they can add another trick: they intercept the method-missing hook and attempt to run any method calls not implemented by the <literal>Image</literal> class as libvips operators. This makes these bindings self-writing: they only contain a small amount of codeand just expose everything they find in the libvips class hierarchy.
|
||||||
|
</para>
|
||||||
|
</refsect3>
|
||||||
|
<refsect3 id="dynamic-langauge-without-ffi">
|
||||||
|
<title>Dynamic langauge without FFI</title>
|
||||||
|
<para>
|
||||||
|
PHP does not have FFI, unfortunately, so for this language a small native module implements the general <literal>vips_call()</literal> function for PHP language types, and a larger pure PHP layer makes it convenient to use.
|
||||||
|
</para>
|
||||||
|
</refsect3>
|
||||||
|
<refsect3 id="gobject-introspection">
|
||||||
|
<title><literal>gobject-introspection</literal></title>
|
||||||
|
<para>
|
||||||
|
The C source code to libvips has been marked up with special comments describing the interface in a standard way. These comments are read by the <literal>gobject-introspection</literal> package when libvips is compiled and used to generate a typelib, a description of how to call the library. Many languages have gobject-introspection packages: all you need to do to call libvips from your favorite language is to start g-o-i, load the libvips typelib, and you should have the whole library available. For example, from Python it’s as simple as:
|
||||||
|
</para>
|
||||||
|
<programlisting language="python">
|
||||||
from gi.repository import Vips
|
from gi.repository import Vips
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
<para>
|
||||||
|
libvips used in this way is likely to be rather bare-bones. For Python, we wrote a set of overrides which layer a more Pythonesque interface on top of the one provided for libvips by pygobject. These overrides are simply a set of Python classes.
|
||||||
<para>
|
</para>
|
||||||
libvips used in this way is likely to be rather bare-bones. For Python,
|
<para>
|
||||||
we wrote a set of overrides which layer a more Pythonesque interface
|
To call a vips operation, you’ll need to 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. The Python binding uses this technique to implement a function which can call any vips operation, turning optional vips arguments into Python keyword arguments.
|
||||||
on top of the one provided for libvips by pygobject. These overrides
|
</para>
|
||||||
are simply a set of Python classes.
|
<para>
|
||||||
</para>
|
You can generate searchable docs from a <code>.gir</code> (the thing that is built from scanning libvips and which in turn turn the typelib is made from) with <command>g-ir-doc-tool</command>, for example:
|
||||||
|
</para>
|
||||||
<para>
|
<programlisting>
|
||||||
To call a vips operation, you'll need to 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.
|
|
||||||
The Python binding uses this technique to implement a function which
|
|
||||||
can call any vips operation, turning optional vips arguments into
|
|
||||||
Python keyword arguments.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
If your language does not have a gobject-introspection package, you'll
|
|
||||||
need to write something in C or C++ doing approximately the same thing.
|
|
||||||
The C++ API takes this route.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
You can generate searchable docs from a <code>.gir</code> (the thing that
|
|
||||||
is built from scanning libvips and which in turn turn the typelib is
|
|
||||||
made from) with <command>g-ir-doc-tool</command>, for example:
|
|
||||||
|
|
||||||
<programlisting language="bash">
|
|
||||||
$ g-ir-doc-tool --language=Python -o ~/mydocs Vips-8.0.gir
|
$ g-ir-doc-tool --language=Python -o ~/mydocs Vips-8.0.gir
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
<para>
|
||||||
Then to view them, either:
|
Then to view them, either:
|
||||||
|
</para>
|
||||||
<programlisting language="bash">
|
<programlisting>
|
||||||
$ yelp ~/mydocs
|
$ yelp ~/mydocs
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
<para>
|
||||||
Or perhaps
|
Or perhaps:
|
||||||
|
</para>
|
||||||
<programlisting language="bash">
|
<programlisting>
|
||||||
$ cd ~/mydocs
|
$ cd ~/mydocs
|
||||||
$ yelp-build html .
|
$ yelp-build html .
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
To make HTML docs. This is an easy way to see what you can call in the library.
|
||||||
|
</para>
|
||||||
|
</refsect3>
|
||||||
|
|
||||||
To make HTML docs. This is an easy way to see what you can call in the
|
|
||||||
library.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
|
|
||||||
</refsect3>
|
|
||||||
|
|
||||||
</refentry>
|
</refentry>
|
||||||
|
@ -32,7 +32,6 @@
|
|||||||
|
|
||||||
<xi:include href="xml/using-command-line.xml"/>
|
<xi:include href="xml/using-command-line.xml"/>
|
||||||
<xi:include href="xml/using-C.xml"/>
|
<xi:include href="xml/using-C.xml"/>
|
||||||
<xi:include href="xml/using-python.xml"/>
|
|
||||||
<xi:include href="xml/using-cpp.xml"/>
|
<xi:include href="xml/using-cpp.xml"/>
|
||||||
<xi:include href="xml/binding.xml"/>
|
<xi:include href="xml/binding.xml"/>
|
||||||
<xi:include href="xml/extending.xml"/>
|
<xi:include href="xml/extending.xml"/>
|
||||||
|
@ -1,681 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
|
||||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
|
||||||
]>
|
|
||||||
<!-- vim: set ts=2 sw=2 expandtab: -->
|
|
||||||
<refentry id="using-from-python">
|
|
||||||
<refmeta>
|
|
||||||
<refentrytitle>VIPS from Python</refentrytitle>
|
|
||||||
<manvolnum>3</manvolnum>
|
|
||||||
<refmiscinfo>VIPS Library</refmiscinfo>
|
|
||||||
</refmeta>
|
|
||||||
|
|
||||||
<refnamediv>
|
|
||||||
<refname>Using VIPS</refname>
|
|
||||||
<refpurpose>How to use the VIPS library from Python</refpurpose>
|
|
||||||
</refnamediv>
|
|
||||||
|
|
||||||
<refsect3 id="python-intro">
|
|
||||||
<title>Introduction</title>
|
|
||||||
<para>
|
|
||||||
VIPS comes with a convenient, high-level Python API built on
|
|
||||||
on <code>gobject-introspection</code>. As long as you can get GOI
|
|
||||||
for your platform, you should be able to use libvips.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
To test the binding, start up Python and at the console enter:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
>>> from gi.repository import Vips
|
|
||||||
>>> x = Vips.Image.new_from_file("/path/to/some/image/file.jpg")
|
|
||||||
>>> x.width
|
|
||||||
1450
|
|
||||||
>>>
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
<orderedlist>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
If import fails, check you have the Python
|
|
||||||
gobject-introspection packages installed, that you have the
|
|
||||||
libvips typelib installed, and that the typelib is either
|
|
||||||
in the system area or on your <code>GI_TYPELIB_PATH</code>.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
If <code>.new_from_file()</code> fails, the vips overrides
|
|
||||||
have not been found. Make sure <code>Vips.py</code> is in
|
|
||||||
your system overrides area.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</orderedlist>
|
|
||||||
</para>
|
|
||||||
</refsect3>
|
|
||||||
|
|
||||||
<refsect3 id="python-example">
|
|
||||||
<title>Example program</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Here's a complete example program:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from gi.repository import Vips
|
|
||||||
|
|
||||||
im = Vips.Image.new_from_file(sys.argv[1])
|
|
||||||
|
|
||||||
im = im.extract_area(100, 100, im.width - 200, im.height - 200)
|
|
||||||
im = im.similarity(scale = 0.9)
|
|
||||||
mask = Vips.Image.new_from_array([[-1, -1, -1],
|
|
||||||
[-1, 16, -1],
|
|
||||||
[-1, -1, -1]], scale = 8)
|
|
||||||
im = im.conv(mask)
|
|
||||||
|
|
||||||
im.write_to_file(sys.argv[2])
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Reading this code, the first interesting line is:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
from gi.repository import Vips
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
When Python executes the import line it performs the following steps:
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<orderedlist>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
It searches for a file called <code>Vips-x.y.typelib</code>. This
|
|
||||||
is a binary file generated automatically during libvips build
|
|
||||||
by introspection of the libvips shared library plus scanning
|
|
||||||
of the C headers. It lists all the API entry points, all the
|
|
||||||
types the library uses, and has an extra set of hints for object
|
|
||||||
ownership and reference counting. The typelib is searched for
|
|
||||||
in <code>/usr/lib/gi-repository-1.0</code> and along the path
|
|
||||||
in the environment variable <code>GI_TYPELIB_PATH</code>.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
It uses the typelib to make a basic binding for libvips. It's
|
|
||||||
just the C API with a little very light mangling, so for
|
|
||||||
example the enum member <code>VIPS_FORMAT_UCHAR</code>
|
|
||||||
of the enum <code>VipsBandFormat</code> becomes
|
|
||||||
<code>Vips.BandFormat.UCHAR</code>.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
The binding you get can be rather unfriendly, so it also
|
|
||||||
loads a set of overrides from <code>Vips.py</code> in
|
|
||||||
<code>/usr/lib/python2.7/dist-packages/gi/overrides</code>
|
|
||||||
(on my system at least). If you're using python3, it's
|
|
||||||
<code>/usr/lib/python3/dist-packages/gi/overrides</code>.
|
|
||||||
Unfortunately, as far as I know, there is no way to extend
|
|
||||||
this search using environment variables. You MUST have
|
|
||||||
<code>Vips.py</code> in exactly this directory. If you install
|
|
||||||
vips via a package manager this will happen automatically,
|
|
||||||
since vips and pygobject will have been built to the same
|
|
||||||
prefix, but if you are installing vips from source and the
|
|
||||||
prefix does not match, it will not be installed for you,
|
|
||||||
you will need to copy it.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Finally, <code>Vips.py</code> makes the rest of the binding. In
|
|
||||||
fact, <code>Vips.py</code> makes almost all the binding: it
|
|
||||||
defines <code>__getattr__</code> on <code>Vips.Image</code>
|
|
||||||
and binds at runtime by searching libvips for an operation of
|
|
||||||
that name.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</orderedlist>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The next line is:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
im = Vips.Image.new_from_file(sys.argv[1])
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
This loads the input image. You can append
|
|
||||||
load options to the argument list as keyword arguments, for example:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
im = Vips.Image.new_from_file(sys.argv[1], access = Vips.Access.SEQUENTIAL)
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
See the various loaders for a list of the available options
|
|
||||||
for each file format. The C equivalent to this function,
|
|
||||||
vips_image_new_from_file(), has more extensive documentation. Try
|
|
||||||
<code>help(Vips.Image)</code> to see a list of all the image
|
|
||||||
constructors --- you can load from memory, create from an array,
|
|
||||||
or create from a constant, for example.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The next line is:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
im = im.extract_area(100, 100, im.width - 200, im.height - 200)
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
The arguments are left, top, width, height, so this crops 100 pixels off
|
|
||||||
every edge. Try <code>help(im.extract_area)</code> and the C API docs
|
|
||||||
for vips_extract_area() for details. You can use <code>.crop()</code>
|
|
||||||
as a synonym, if you like.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
<code>im.width</code> gets the image width
|
|
||||||
in pixels, see <code>help(Vips.Image)</code> and vips_image_get_width()
|
|
||||||
and friends for a list of the other getters.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The next line:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
im = im.similarity(scale = 0.9)
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
shrinks by 10%. By default it uses
|
|
||||||
bilinear interpolation, use <code>interpolate</code> to pick another
|
|
||||||
interpolator, for example:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
im = im.similarity(scale = 0.9, interpolate = Vips.Interpolate.new("bicubic"))
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
see vips_similarity() for full documentation. The similarity operator
|
|
||||||
will not give good results for large resizes (more than a factor of
|
|
||||||
two). See vips_resize() if you need to make a large change.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Next:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
mask = Vips.Image.new_from_array([[-1, -1, -1],
|
|
||||||
[-1, 16, -1],
|
|
||||||
[-1, -1, -1]], scale = 8)
|
|
||||||
im = im.conv(mask)
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
makes an image from a 2D array, then convolves with that. The
|
|
||||||
<code>scale</code> keyword argument lets you set a divisor for
|
|
||||||
convolution, handy for integer convolutions. You can set
|
|
||||||
<code>offset</code> as well. See vips_conv() for details on the vips
|
|
||||||
convolution operator.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Finally,
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
im.write_to_file(sys.argv[2])
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
sends the image back to the
|
|
||||||
filesystem. There's also <code>.write_to_buffer()</code> to make a
|
|
||||||
string containing the formatted image, and <code>.write()</code> to
|
|
||||||
write to another image.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
As with <code>.new_from_file()</code> you can append save options as
|
|
||||||
keyword arguments. For example:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
im.write_to_file("test.jpg", Q = 90)
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
will write a JPEG image with quality set to 90. See the various save
|
|
||||||
operations for a list of all the save options, for example
|
|
||||||
vips_jpegsave().
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</refsect3>
|
|
||||||
|
|
||||||
<refsect3 id="python-doc">
|
|
||||||
<title>Getting help</title>
|
|
||||||
<para>
|
|
||||||
Try <code>help(Vips)</code> for everything,
|
|
||||||
<code>help(Vips.Image)</code> for something slightly more digestible, or
|
|
||||||
something like <code>help(Vips.Image.black)</code> for help on a
|
|
||||||
specific class member.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
You can't get help on dynamically bound member functions like
|
|
||||||
<code>.add()</code> this way. Instead, make an image and get help
|
|
||||||
from that, for example:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
image = Vips.Image.black(1, 1)
|
|
||||||
help(image.add)
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
And you'll get a summary of the operator's behaviour and how the
|
|
||||||
arguments are represented in Python.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The API docs have a <link linkend="function-list">handy table of all vips
|
|
||||||
operations</link>, if you want to find out how to do something, try
|
|
||||||
searching that.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The <command>vips</command> command can be useful too. For example, in a
|
|
||||||
terminal you can type <command>vips jpegsave</command> to get a
|
|
||||||
summary of an operation:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
$ vips jpegsave
|
|
||||||
save image to jpeg file
|
|
||||||
usage:
|
|
||||||
jpegsave in filename
|
|
||||||
where:
|
|
||||||
in - Image to save, input VipsImage
|
|
||||||
filename - Filename to save to, input gchararray
|
|
||||||
optional arguments:
|
|
||||||
Q - Q factor, input gint
|
|
||||||
default: 75
|
|
||||||
min: 1, max: 100
|
|
||||||
profile - ICC profile to embed, input gchararray
|
|
||||||
optimize-coding - Compute optimal Huffman coding tables, input gboolean
|
|
||||||
default: false
|
|
||||||
interlace - Generate an interlaced (progressive) jpeg, input gboolean
|
|
||||||
default: false
|
|
||||||
no-subsample - Disable chroma subsample, input gboolean
|
|
||||||
default: false
|
|
||||||
trellis-quant - Apply trellis quantisation to each 8x8 block, input gboolean
|
|
||||||
default: false
|
|
||||||
overshoot-deringing - Apply overshooting to samples with extreme values, input gboolean
|
|
||||||
default: false
|
|
||||||
optimize-scans - Split the spectrum of DCT coefficients into separate scans, input gboolean
|
|
||||||
default: false
|
|
||||||
strip - Strip all metadata from image, input gboolean
|
|
||||||
default: false
|
|
||||||
background - Background value, input VipsArrayDouble
|
|
||||||
operation flags: sequential-unbuffered nocache
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
</refsect3>
|
|
||||||
|
|
||||||
<refsect3 id="python-basics">
|
|
||||||
<title><code>pyvips8</code> basics</title>
|
|
||||||
<para>
|
|
||||||
As noted above, the Python interface comes in two main parts,
|
|
||||||
an automatically generated binding based on the vips typelib,
|
|
||||||
plus a set of extra features provided by overrides.
|
|
||||||
The rest of this chapter runs through the features provided by the
|
|
||||||
overrides.
|
|
||||||
</para>
|
|
||||||
</refsect3>
|
|
||||||
|
|
||||||
<refsect3 id="python-wrapping">
|
|
||||||
<title>Automatic wrapping</title>
|
|
||||||
<para>
|
|
||||||
The overrides intercept member lookup
|
|
||||||
on the <code>Vips.Image</code> class and look for vips operations
|
|
||||||
with that name. So the vips operation "add", which appears in the
|
|
||||||
C API as vips_add(), appears in Python as
|
|
||||||
<code>image.add()</code>.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The first input image argument becomes the <code>self</code>
|
|
||||||
argument. If there are no input image arguments, the operation
|
|
||||||
appears as a class member. Optional input arguments become
|
|
||||||
keyword arguments. The result is a list of all the output
|
|
||||||
arguments, or a single output if there is only one.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Optional output arguments are enabled with a boolean keyword
|
|
||||||
argument of that name. For example, "min" (the operation which
|
|
||||||
appears in the C API as vips_min()), can be called like this:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
min_value = im.min()
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
and <code>min_value</code> will be a floating point value giving
|
|
||||||
the minimum value in the image. "min" can also find the position
|
|
||||||
of the minimum value with the <code>x</code> and <code>y</code>
|
|
||||||
optional output arguments. Call it like this:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
min_value, opts = im.min(x = True, y = True)
|
|
||||||
x = opts['x']
|
|
||||||
y = opts['y']
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
In other words, if optional output args are requested, an extra
|
|
||||||
dictionary is returned containing those objects.
|
|
||||||
Of course in this case, the <code>.minpos()</code> convenience
|
|
||||||
function would be simpler, see below.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Because operations are member functions and return the result image,
|
|
||||||
you can chain them. For example, you can write:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
result_image = image.sin().pow(2)
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
to calculate the square of the sine for each pixel. There is also a
|
|
||||||
full set of arithmetic operator overloads, see below.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
VIPS types are also automatically wrapped. The override looks
|
|
||||||
at the type of argument required by the operation and converts
|
|
||||||
the value you supply, when it can. For example, "linear" takes a
|
|
||||||
#VipsArrayDouble as an argument for the set of constants to use for
|
|
||||||
multiplication. You can supply this value as an integer, a float,
|
|
||||||
or some kind of compound object and it will be converted for you.
|
|
||||||
You can write:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
result_image = image.linear(1, 3)
|
|
||||||
result_image = image.linear(12.4, 13.9)
|
|
||||||
result_image = image.linear([1, 2, 3], [4, 5, 6])
|
|
||||||
result_image = image.linear(1, [4, 5, 6])
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
And so on. A set of overloads are defined for <code>.linear()</code>,
|
|
||||||
see below.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
It does a couple of more ambitious conversions. It will
|
|
||||||
automatically convert to and from the various vips types,
|
|
||||||
like #VipsBlob and #VipsArrayImage. For example, you can read the
|
|
||||||
ICC profile out of an image like this:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
profile = im.get_value("icc-profile-data")
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
and <code>profile</code> will be a string.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
You can use array constants instead of images. A 2D array is simply
|
|
||||||
changed into a one-band double image. This is handy for things like
|
|
||||||
<code>.erode()</code>, for example:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
im = im.erode([[128, 255, 128],
|
|
||||||
[255, 255, 255],
|
|
||||||
[128, 255, 128]])
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
will erode an image with a 4-connected structuring element.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
If an operation takes several input images, you can use a 1D array
|
|
||||||
constant or a number constant
|
|
||||||
for all but one of them and the wrapper will expand it
|
|
||||||
to an image for you. For example, <code>.ifthenelse()</code> uses
|
|
||||||
a condition image to pick pixels between a then and an else image:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
result_image = condition_image.ifthenelse(then_image, else_image)
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
You can use a constant instead of either the then or the else
|
|
||||||
parts, and it will be expanded to an image for you. If you use a
|
|
||||||
constant for both then and else, it will be expanded to match the
|
|
||||||
condition image. For example:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
result_image = condition_image.ifthenelse([0, 255, 0], [255, 0, 0])
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
Will make an image where true pixels are green and false pixels
|
|
||||||
are red.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
This is also useful for <code>.bandjoin()</code>, the thing to join
|
|
||||||
two or more images up bandwise. You can write:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
rgba = rgb.bandjoin(255)
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
to add a constant 255 band to an image, perhaps to add an alpha
|
|
||||||
channel. Of course you can also write:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
result_image = image1.bandjoin(image2)
|
|
||||||
result_image = image1.bandjoin([image2, image3])
|
|
||||||
result_image = image1.bandjoin([image2, 255])
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
and so on.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</refsect3>
|
|
||||||
|
|
||||||
<refsect3 id="python-exceptions">
|
|
||||||
<title>Exceptions</title>
|
|
||||||
<para>
|
|
||||||
The wrapper spots errors from vips operations and raises the
|
|
||||||
<code>Vips.Error</code> exception. You can catch it in the
|
|
||||||
usual way. The <code>.detail</code> member gives the detailed
|
|
||||||
error message.
|
|
||||||
</para>
|
|
||||||
</refsect3>
|
|
||||||
|
|
||||||
<refsect3 id="python-memory">
|
|
||||||
<title>Reading and writing areas of memory</title>
|
|
||||||
<para>
|
|
||||||
You can use the C API functions vips_image_new_from_memory(),
|
|
||||||
vips_image_new_from_memory_copy() and
|
|
||||||
vips_image_write_to_memory() directly from Python to read and write
|
|
||||||
areas of memory. This can be useful if you need to get images to and
|
|
||||||
from other other image processing libraries, like PIL or numpy.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Use them from Python like this:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
image = Vips.Image.new_from_file("/path/to/some/image/file.jpg")
|
|
||||||
memory_area = image.write_to_memory()
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
<code>memory_area</code> is now a string containing uncompressed binary
|
|
||||||
image data. For an RGB image, it will have bytes
|
|
||||||
<code>RGBRGBRGB...</code>, being
|
|
||||||
the first three pixels of the first scanline of the image. You can pass
|
|
||||||
this string to the numpy or PIL constructors and make an image there.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Note that <code>.write_to_memory()</code> will make a copy of the image.
|
|
||||||
It would
|
|
||||||
be better to use a Python buffer to pass the data, but sadly this isn't
|
|
||||||
possible with gobject-introspection, as far as I know.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Going the other way, you can construct a vips image from a string of
|
|
||||||
binary data. For example:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
image = Vips.Image.new_from_file("/path/to/some/image/file.jpg")
|
|
||||||
memory_area = image.write_to_memory()
|
|
||||||
image2 = Vips.Image.new_from_memory(memory_area,
|
|
||||||
image.width, image.height, image.bands,
|
|
||||||
Vips.BandFormat.UCHAR)
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
Now <code>image2</code> should be an identical copy of <code>image</code>.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Be careful: in this direction, vips does not make a copy of the memory
|
|
||||||
area, so if <code>memory_area</code> is freed by the Python garbage
|
|
||||||
collector and
|
|
||||||
you later try to use <code>image2</code>, you'll get a crash.
|
|
||||||
Make sure you keep a reference to <code>memory_area</code> around
|
|
||||||
for as long as you need it. A simple solution is to use
|
|
||||||
<code>new_from_memory_copy</code> instead. This will take a copy of the
|
|
||||||
memory area for vips. Of course this will raise memory usage.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</refsect3>
|
|
||||||
|
|
||||||
<refsect3 id="python-modify">
|
|
||||||
<title>Draw operations</title>
|
|
||||||
<para>
|
|
||||||
Paint operations like <code>draw_circle</code> and <code>draw_line</code>
|
|
||||||
modify their input image. This makes them hard to use with the rest of
|
|
||||||
libvips: you need to be very careful about the order in which operations
|
|
||||||
execute or you can get nasty crashes.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The wrapper spots operations of this type and makes a private copy of
|
|
||||||
the image in memory before calling the operation. This stops crashes,
|
|
||||||
but it does make it inefficient. If you draw 100 lines on an image,
|
|
||||||
for example, you'll copy the image 100 times. The wrapper does make sure
|
|
||||||
that memory is recycled where possible, so you won't have 100 copies in
|
|
||||||
memory. At least you can execute these operations.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
If you want to avoid the copies, you'll need to call drawing
|
|
||||||
operations yourself.
|
|
||||||
</para>
|
|
||||||
</refsect3>
|
|
||||||
|
|
||||||
<refsect3 id="python-overloads">
|
|
||||||
<title>Overloads</title>
|
|
||||||
<para>
|
|
||||||
The wrapper defines the usual set of arithmetic, boolean and
|
|
||||||
relational overloads on
|
|
||||||
<code>image</code>. You can mix images, constants and lists of
|
|
||||||
constants (almost) freely. For example, you can write:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
result_image = ((image * [1, 2, 3]).abs() < 128) | 4
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The wrapper overloads <code>[]</code> to be vips_extract_band(). You
|
|
||||||
can write:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
result_image = image[2]
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
to extract the third band of the image. It implements the usual
|
|
||||||
slicing and negative indexes, so you can write:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
result_image = image[1:]
|
|
||||||
result_image = image[:3]
|
|
||||||
result_image = image[-2:]
|
|
||||||
result_image = [x.avg() for x in image]
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
and so on.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The wrapper overloads <code>()</code> to be vips_getpoint(). You can
|
|
||||||
write:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
r, g, b = image(10, 10)
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
to read out the value of the pixel at coordinates (10, 10) from an RGB
|
|
||||||
image.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</refsect3>
|
|
||||||
|
|
||||||
<refsect3 id="python-expansions">
|
|
||||||
<title>Expansions</title>
|
|
||||||
<para>
|
|
||||||
Some vips operators take an enum to select an action, for example
|
|
||||||
<code>.math()</code> can be used to calculate sine of every pixel
|
|
||||||
like this:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
result_image = image.math(Vips.OperationMath.SIN)
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
This is annoying, so the wrapper expands all these enums into
|
|
||||||
separate members named after the enum. So you can write:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
result_image = image.sin()
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
See <code>help(Vips.Image)</code> for a list.
|
|
||||||
</para>
|
|
||||||
</refsect3>
|
|
||||||
|
|
||||||
<refsect3 id="python-utility">
|
|
||||||
<title>Convenience functions</title>
|
|
||||||
<para>
|
|
||||||
The wrapper defines a few extra useful utility functions:
|
|
||||||
<code>.get_value()</code>,
|
|
||||||
<code>.set_value()</code>,
|
|
||||||
<code>.bandsplit()</code>,
|
|
||||||
<code>.maxpos()</code>,
|
|
||||||
<code>.minpos()</code>,
|
|
||||||
<code>.median()</code>.
|
|
||||||
Again, see <code>help(Vips.Image)</code> for a list.
|
|
||||||
</para>
|
|
||||||
</refsect3>
|
|
||||||
|
|
||||||
<refsect3 id="python-args">
|
|
||||||
<title>Command-line option parsing</title>
|
|
||||||
<para>
|
|
||||||
GLib includes a command-line option parser, and Vips defines a set of
|
|
||||||
standard flags you can use with it. For example:
|
|
||||||
|
|
||||||
<programlisting language="Python">
|
|
||||||
import sys
|
|
||||||
from gi.repository import GLib, Vips
|
|
||||||
|
|
||||||
context = GLib.OptionContext(" - test stuff")
|
|
||||||
main_group = GLib.OptionGroup("main",
|
|
||||||
"Main options", "Main options for this program",
|
|
||||||
None)
|
|
||||||
context.set_main_group(main_group)
|
|
||||||
Vips.add_option_entries(main_group)
|
|
||||||
context.parse(sys.argv)
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</refsect3>
|
|
||||||
|
|
||||||
</refentry>
|
|
Loading…
Reference in New Issue
Block a user