diff --git a/ChangeLog b/ChangeLog index 913fda72..b55ced7b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 diff --git a/TODO b/TODO index eb4cab9b..cfc96742 100644 --- a/TODO +++ b/TODO @@ -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? diff --git a/doc/src/format.tex b/doc/src/format.tex index 227a9dbf..63c45d10 100644 --- a/doc/src/format.tex +++ b/doc/src/format.tex @@ -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 diff --git a/doc/src/interpolate.tex b/doc/src/interpolate.tex new file mode 100644 index 00000000..7e4a1846 --- /dev/null +++ b/doc/src/interpolate.tex @@ -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} + diff --git a/doc/src/vipsmanual.tex b/doc/src/vipsmanual.tex index 30750e1c..744394bd 100644 --- a/doc/src/vipsmanual.tex +++ b/doc/src/vipsmanual.tex @@ -73,6 +73,7 @@ This manual formatted \today \input{iosys} \input{func} \input{format} +\input{interpolate} \chapter{Writing VIPS operations} diff --git a/include/vips/object.h b/include/vips/object.h index fd2b93c8..b20f1a3d 100644 --- a/include/vips/object.h +++ b/include/vips/object.h @@ -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 ); diff --git a/libsrc/iofuncs/object.c b/libsrc/iofuncs/object.c index 334e4146..e307dd29 100644 --- a/libsrc/iofuncs/object.c +++ b/libsrc/iofuncs/object.c @@ -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 diff --git a/libsrc/mosaicing/interpolate.c b/libsrc/mosaicing/interpolate.c index c3493049..695416d4 100644 --- a/libsrc/mosaicing/interpolate.c +++ b/libsrc/mosaicing/interpolate.c @@ -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, diff --git a/man/im_affine.3 b/man/im_affine.3 index d105f1a2..be5b4405 100644 --- a/man/im_affine.3 +++ b/man/im_affine.3 @@ -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) diff --git a/man/im_affinei.3 b/man/im_affinei.3 new file mode 100644 index 00000000..49376c1d --- /dev/null +++ b/man/im_affinei.3 @@ -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 + +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) diff --git a/man/im_affinei_all.3 b/man/im_affinei_all.3 new file mode 100644 index 00000000..37d2ee21 --- /dev/null +++ b/man/im_affinei_all.3 @@ -0,0 +1 @@ +.so man3/im_affinei.3 diff --git a/man/vips.1 b/man/vips.1 index 7ddc8ada..aa095b71 100644 --- a/man/vips.1 +++ b/man/vips.1 @@ -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 diff --git a/src/iofuncs/vips.c b/src/iofuncs/vips.c index 41eb3fe1..74e55ad5 100644 --- a/src/iofuncs/vips.c +++ b/src/iofuncs/vips.c @@ -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" ),