This commit is contained in:
John Cupitt 2009-02-18 10:04:10 +00:00
parent 26dff6bb73
commit 158a933151
13 changed files with 263 additions and 69 deletions

View File

@ -33,6 +33,7 @@
- added "nickname" and "description" properties to VipsObject
- shift/and/or/eor ops were broken for non-int types
- added nohalo interpolator
- updated format docs
- IM_INPUT_INTERPOLATE() now used by affinei and affinei_all
11/9/08 started 7.16.3

17
TODO
View File

@ -1,16 +1,17 @@
- make properties for nickname etc. so we can get class properties from
objects
- dir on a Managedgobject should list properties
- interpolate.c never calls vips_object_build() for bilinear etc., is this OK?
- (get_member "poop" (Managedgobject)) should work
try to add this
- dir on a gtype should also list properties? how should we list subclasses?
- need to write interpolate docs ... manpages and tutorial
difficult without docs for vips_object
- need a section for vipsobject in the tutorial
also a manpage?
- maybe IM_INTERPOLATE() isn't a good idea? maybe just IM_GOBJECT?
not really stable yet :( don't document
- try making vips_add(), an operator as a class
@ -18,9 +19,7 @@
- make a "deprecated" package too
- im_affinei and im_affinei_all need docs
- update format docs
- remove yafrnohalo.c
- how to expose things like yafrsmooth's "sharpening" parameter to
C++/Python?

View File

@ -2,7 +2,7 @@
\label{sec:format}
VIPS has a simple system for adding support for new image file formats.
You can ask VIPS to find a format to load a file with,
You can ask VIPS to find a format to load a file with
or to select a image file writer based on a filename. Convenience functions
copy a file to an \verb+IMAGE+, or an \verb+IMAGE+ to a file. New formats may
be added to VIPS by simply defining a new subclass of \verb+VipsFormat+.
@ -42,7 +42,17 @@ version is one indicating that the file can be opened lazily
\end{itemize}
\subsection{The format table}
A switch to the \verb+vips+ command-line program is handy for listing the
supported formats. Try:
\begin{verbatim}
vips --list classes
\end{verbatim}
\noindent
And look for subclasses of \verb+VipsFormat+.
\subsection{The format class}
The interface to the format system is defined by the abstract base class
\verb+VipsFormat+. Formats subclass this and implement some or all of the
@ -50,13 +60,6 @@ methods. Any of the functions may be left NULL and VIPS will try to make do
with what you do supply. Of course a format with all functions as NULL will
not be very useful.
A switch to the \verb+vips+ command-line program is handy for listing the
supported formats. Try:
\begin{verbatim}
vips --list formats
\end{verbatim}
As an example, \fref{fg:newformat} shows how to register a new format in a
plugin.
@ -82,7 +85,7 @@ typedef VipsFormat VipsFormatMyformat;
typedef VipsFormatClass VipsFormatMyformatClass;
static void
vips_format_myformat_class_init( VipsFormatVipsClass *class )
vips_format_myformat_class_init( VipsFormatMyformatClass *class )
{
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsFormatClass *format_class = (VipsFormatClass *) class;
@ -100,17 +103,17 @@ vips_format_myformat_class_init( VipsFormatVipsClass *class )
}
static void
vips_format_vips_init( VipsFormatVips *object )
vips_format_myformat_init( VipsFormatMyformat *object )
{
}
G_DEFINE_TYPE( VipsFormatVips, vips_format_vips, VIPS_TYPE_FORMAT );
G_DEFINE_TYPE( VipsFormatMyformat, vips_format_myformat, VIPS_TYPE_FORMAT );
char *
g_module_check_init( GModule *self )
{
// register the type
vips_format_vips_get_type();
vips_format_myformat_get_type();
}
\end{verbatim}
\caption{Registering a format in a plugin}
@ -119,14 +122,15 @@ g_module_check_init( GModule *self )
\subsection{Finding a format}
You can loop over the format table in order with \verb+vips_format_map()+. Like
all the map functions in VIPS, this take a function and applies it to every
element in the table until it returns non-zero, or until the table ends.
You can loop over the subclasses of \verb+VipsFormat+ in order of priority
with \verb+vips_format_map()+. Like all the map functions in VIPS, this take
a function and applies it to every element in the table until the function
returns non-zero or until the table ends.
You find an \verb+VipsFormatClass+ to use to open a file with
\verb+vips_format_for_file()+. This searches the type system and returns
the first format whose test function returns true, setting an error message
and returning NULL if no format is found.
\verb+vips_format_for_file()+. This finds the first format whose \verb+is_a()+
function returns true or whose suffix list matches the suffix of the filename,
setting an error message and returning NULL if no format is found.
You find a format to write a file with \verb+vips_format_for_name()+. This
returns the first format with a save function whose suffix list matches the

110
doc/src/interpolate.tex Normal file
View File

@ -0,0 +1,110 @@
\section{Interpolators}
\label{sec:interpolate}
VIPS has a general system for representing pixel interpolators. You can select
an interpolator to pass to other VIPS operations, such as \verb+im_affinei()+,
you can add new interpolators, and you can write operations which take a
general interpolator as a parameter.
An interpolator is a function of the form:
\begin{verbatim}
typedef void (*VipsInterpolateMethod)( VipsInterpolate *,
PEL *out, REGION *in, double x, double y );
\end{verbatim}
\noindent
Given the set of input pixels \verb+in+, it has to calculate a value for the
fractional position $(x, y)$ and write this value to the memory pointed to by
\verb+out+.
VIPS uses corner convention, so the value of pixel $(0, 0)$ is the value of
the surface the interpolator fits at the fractional position $(0.0, 0.0)$.
\subsection{How an interpolator is represented}
See the man page for \verb+VipsInterpolate+ for full details, but briefly,
an interpolator is a subclass of \verb+VipsInterpolate+ implementing the
following items:
\begin{itemize}
\item
An interpolation method, with the type signature above.
\item
A function \verb+get_window_size()+ which returns the size of the area of
pixels that the interpolator needs in order to calculate a value. For example,
a bilinear interpolator needs the four pixels surrounding the point to be
calculated, or a 2 by 2 window, so window size should be 2.
\item
Or if the window size is constant, you can leave \verb+get_window_size()+
NULL and just set the int value \verb+window_size+.
\end{itemize}
A switch to the \verb+vips+ command-line program is handy for listing the
supported interpolators. Try:
\begin{verbatim}
vips --list classes
\end{verbatim}
\noindent
And look for subclasses of \verb+VipsInterpolate+.
\subsection{A sample interpolator}
As an example, \fref{fg:newinterpolator} shows how to register a new
interpolator in a plugin.
\begin{fig2}
\begin{verbatim}
// This interpolator adds no new members.
typedef VipsInterpolate VipsInterpolateMyinterpolator;
typedef VipsInterpolateClass VipsInterpolateMyinterpolator;
static void
vips_interpolate_myinterpolator_interpolate( VipsInterpolate *interpolate,
PEL *out, REGION *in, double x, double y )
{
VipsInterpolateBilinearClass *class =
VIPS_INTERPOLATE_BILINEAR_GET_CLASS( interpolate );
static void
vips_interpolate_myinterpolator_class_init(
VipsInterpolateMyinterpolatorClass *class )
{
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsInterpolateClass *interpolate_class = (VipsInterpolateClass *) class;
object_class->nickname = "myinterpolator";
object_class->description = _( "My interpolator" );
interpolate_class->interpolate = my_interpolate;
}
static void
vips_interpolate_myinterpolate_init( VipsInterpolateMyinterpolate *object )
{
}
G_DEFINE_TYPE( VipsInterpolateMyinterpolator, vips_interpolate_myinterpolator,
VIPS_TYPE_INTERPOLATE );
char *
g_module_check_init( GModule *self )
{
// register the type
vips_format_myformat_get_type();
}
\end{verbatim}
\caption{Registering an interpolator in a plugin}
\label{fg:newinterpolator}
\end{fig2}
\subsection{Passing an interpolator to a VIPS operation}
\subsection{Writing a VIPS operation that takes an interpolator as an argument}

View File

@ -73,6 +73,7 @@ This manual formatted \today
\input{iosys}
\input{func}
\input{format}
\input{interpolate}
\chapter{Writing VIPS operations}

View File

@ -241,6 +241,10 @@ GType vips_object_get_type( void );
void vips_object_class_install_argument( VipsObjectClass *,
GParamSpec *pspec, VipsArgumentFlags flags, guint offset );
typedef void *(*VipsObjectSetArguments)( VipsObject *, void *, void * );
VipsObject *vips_object_new( GType type,
VipsObjectSetArguments set, void *a, void *b );
VipsObject *vips_object_new_from_string( const char *base, const char *str );
void vips_object_to_string( VipsObject *object, VipsBuf *buf );

View File

@ -220,7 +220,8 @@ vips_argument_init2( VipsObject *object, GParamSpec *pspec,
/* Create a VipsArgumentInstance for each installed argument property. Ideally
* we'd do this during _init() but g_object_class_find_property() does not seem
* to work then :-( so we have to delay it until first access.
* to work then :-( so we have to delay it until first access. See
* vips__argument_get_instance().
*/
static void
vips_argument_init( VipsObject *object )
@ -699,6 +700,10 @@ vips_object_real_build( VipsObject *object )
"nickname", object_class->nickname,
"description", object_class->description, NULL );
/* Signal changed, since all properties should now be set.
*/
vips_object_changed( object );
return( result );
}
@ -952,6 +957,41 @@ vips_object_set_args( VipsObject *object, const char *p )
return( 0 );
}
VipsObject *
vips_object_new( GType type, VipsObjectSetArguments set, void *a, void *b )
{
VipsObject *object;
object = VIPS_OBJECT( g_object_new( type, NULL ) );
if( set( object, a, b ) ||
vips_object_build( object ) ) {
g_object_unref( object );
return( NULL );
}
return( object );
}
static void *
vips_object_new_from_string_set( VipsObject *object, void *a, void *b )
{
const char *p = (const char *) a;
VipsToken token;
char string[PATH_MAX];
if( (p = vips__token_get( p, &token, string, PATH_MAX )) ) {
if( token == VIPS_TOKEN_LEFT &&
vips_object_set_args( object, p ) ) {
im_error( "object_new", "%s",
_( "bad object arguments" ) );
return( object );
}
}
return( NULL );
}
VipsObject *
vips_object_new_from_string( const char *basename, const char *p )
{
@ -964,24 +1004,8 @@ vips_object_new_from_string( const char *basename, const char *p )
!(type = vips_type_find( basename, string )) )
return( NULL );
object = VIPS_OBJECT( g_object_new( type, NULL ) );
if( (p = vips__token_get( p, &token, string, PATH_MAX )) ) {
if( token == VIPS_TOKEN_LEFT &&
vips_object_set_args( object, p ) ) {
im_error( "object_new", "%s",
_( "bad object arguments" ) );
g_object_unref( object );
return( NULL );
}
}
if( vips_object_build( object ) ) {
g_object_unref( object );
return( NULL );
}
return( object );
return( vips_object_new( type,
vips_object_new_from_string_set, (void *) p, NULL ) );
}
static void

View File

@ -100,7 +100,7 @@ vips_interpolate_init( VipsInterpolate *interpolate )
}
/* Set the point out_x, out_y in REGION out to be the point interpolated at
* in_x, in_y in REGION in. Don't do this as a signal ffor speed.
* in_x, in_y in REGION in. Don't do this as a signal for speed.
*/
void
vips_interpolate( VipsInterpolate *interpolate,

View File

@ -15,7 +15,11 @@ int im_affine(in, out, a, b, c, d, dx, dy, x, y, w, h)
.B int w, h;
.SH DESCRIPTION
.B im_affine()
This function is deprecated. See
.B im_affine(3)
for the replacement.
.B im_affine(3)
applies an affine transformation on the image held by the IMAGE descriptor
in and puts the result at the location pointed by the IMAGE descriptor out. in
many have any number of bands, be any size, and have any non-complex type.
@ -23,26 +27,15 @@ many have any number of bands, be any size, and have any non-complex type.
The transformation is described by a, b, c, d, dx, dy. The point (x,y) in
the input is mapped onto point (X,Y) in the output by
X = a * x + b * y + dx
Y = c * x + d * y + dy
X = a * x + b * y + dx
Y = c * x + d * y + dy
The area of the output image given by w, h, x, y is generated. (0,0) is
the position of the transformed top-left-hand corner of the input image.
Function im_affine resamples the transformed image using bilinear
interpolation.
You can use
.B im_affine(3)
to resize an image with something like:
scale xfac yfac im
= im_affine im xfac 0 0 yfac 0 0 0 0
(im.width * xfac) (im.height * yfac);
.SH RETURN VALUE
The functions return 0 on success and -1 on error.
.SH BUGS
As with most resamplers, im_affine(3) performs poorly at the edges of
images.
.SH SEE ALSO
im_similarity(3)

58
man/im_affinei.3 Normal file
View File

@ -0,0 +1,58 @@
.TH IM_AFFINEI 3 "8 February 2009"
.SH NAME
im_affinei \- apply an affine transform to an image
.SH SYNOPSIS
.B #include <vips/vips.h>
int im_affinei(in, out, interpolate, a, b, c, d, dx, dy, x, y, w, h)
.br
.B IMAGE *in, *out;
.br
.B VipsInterpolate *interpolate;
.br
.B double a, b, c, d, dx, dy;
.br
.B int x, y;
.br
.B int w, h;
int im_affinei_all(in, out, interpolate, a, b, c, d, dx, dy)
.br
.B IMAGE *in, *out;
.br
.B VipsInterpolate *interpolate;
.br
.B double a, b, c, d, dx, dy;
.SH DESCRIPTION
.B im_affinei()
applies an affine transformation on the image held by the IMAGE descriptor
in and puts the result at the location pointed by the IMAGE descriptor out. in
many have any number of bands, be any size, and have any non-complex type.
The transformation is described by a, b, c, d, dx, dy. The point (x,y) in
the input is mapped onto point (X,Y) in the output by
X = a * x + b * y + dx
Y = c * x + d * y + dy
The area of the output image given by w, h, x, y is generated. (0,0) is
the position of the transformed top-left-hand corner of the input image.
Points are generated using the supplied interpolator. See
.B VipsInterpolate(3)
for a list of the interpolators that come with vips.
.B im_affinei_all(3)
is a convenience function that transforms the whole of the input image. It
calls
.B im_affine(3)
for you, with x y w h set to exactly enclose the transformed image.
.SH RETURN VALUE
The functions return 0 on success and -1 on error.
.SH BUGS
As with most resamplers, im_affine(3) performs poorly at the edges of
images.
.SH SEE ALSO
im_similarity(3)

1
man/im_affinei_all.3 Normal file
View File

@ -0,0 +1 @@
.so man3/im_affinei.3

View File

@ -23,7 +23,8 @@ then you can use that link to call an operation directly. For example:
.SH OPTIONS
.TP
.B -l PACKAGE, --list=PACKAGE
List operations defined in PACKAGE.
List operations defined in PACKAGE. PACKAGE can also be "classes", "packages"
or "all".
.TP
.B -u OPERATION, --usage=OPERATION
@ -45,11 +46,6 @@ Print C++ header for PACKAGE. PACKAGE can also be a function name, or "all".
.B -c PACKAGE, --cppc=PACKAGE
Print C++ binding for PACKAGE. PACKAGE can also be a function name, or "all".
.TP
.B -s PACKAGE, --swig=PACKAGE
Print SWIG declaration for PACKAGE. PACKAGE can also be a function name,
or "all".
.SH RETURN VALUE
returns 0 on success and non-zero on error.
.SH SEE ALSO

View File

@ -28,6 +28,8 @@
* - add --list formats
* 29/11/08
* - add --list interpolators
* 9/2/09
* - and now we just have --list packages/classes/package-name
*/
/*
@ -86,7 +88,8 @@ static gboolean *main_option_version;
static GOptionEntry main_option[] = {
{ "list", 'l', 0, G_OPTION_ARG_STRING, &main_option_list,
N_( "list operations in PACKAGE (or \"all\", \"packages\")" ),
N_( "list operations in PACKAGE "
"(or \"all\", \"packages\", \"classes\")" ),
"PACKAGE" },
{ "usage", 'u', 0, G_OPTION_ARG_STRING, &main_option_usage,
N_( "show usage message for OPERATION" ),