From a584569881aac7fb6fa38918812c5838a19e4ba3 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 8 Oct 2009 14:02:38 +0000 Subject: [PATCH] stuff --- ChangeLog | 3 +- TODO | 9 ++- doc/reference/libvips-docs.sgml.in | 2 +- libvips/format/format.c | 11 +++ libvips/include/vips/image.h | 14 ++++ libvips/include/vips/region.h | 11 +-- libvips/iofuncs/Makefile.am | 1 - libvips/iofuncs/im_demand_hint.c | 95 ++++++++++------------- libvips/iofuncs/im_generate.c | 49 ++++++++++++ libvips/iofuncs/im_init.c | 4 + libvips/iofuncs/im_iterate.c | 17 ++++- libvips/iofuncs/im_prepare.c | 3 +- libvips/iofuncs/im_wrapmany.c | 118 +++++++++++++++++++++++------ libvips/iofuncs/im_wraptwo.c | 103 ------------------------- 14 files changed, 242 insertions(+), 198 deletions(-) delete mode 100644 libvips/iofuncs/im_wraptwo.c diff --git a/ChangeLog b/ChangeLog index 5f65d583..d97e42ed 100644 --- a/ChangeLog +++ b/ChangeLog @@ -51,11 +51,12 @@ - added im_flood_other() as start of simple segmentation operator - added im_segment() - im_printlines(), im_debugim() deprecated (use im_vips2csv() instead) -- meta, header, callback, error, REGION gtkdocs +- meta, header, callback, error, region gtkdocs - removed printlines tool, vips2csv is much better - removed other useless tools as well: debugim, binfile - fix up addr calcs on 64-bit machines with >2gb images and inplace ops (thanks Christoph) +- im_generate() checks that im_demand_hint() has been called for this image 25/3/09 started 7.18.0 - revised version numbers diff --git a/TODO b/TODO index 03ad2184..aa17f946 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,11 @@ -- reached im_iterate() in region.h +- region needs to be broken up + + split prepare, generate etc. out to another chapter, maybe generate.h + + +- VipsFormat next? where should we document the im_vip2jpeg() options? -- inplace ops break over 2gb? insert_inplace especially - - more stuff from util.c? too much to do it all now - im_render()? diff --git a/doc/reference/libvips-docs.sgml.in b/doc/reference/libvips-docs.sgml.in index a0efbfac..6e8fd432 100644 --- a/doc/reference/libvips-docs.sgml.in +++ b/doc/reference/libvips-docs.sgml.in @@ -22,6 +22,7 @@ + @@ -39,7 +40,6 @@ - diff --git a/libvips/format/format.c b/libvips/format/format.c index 0c2165a0..e35c8144 100644 --- a/libvips/format/format.c +++ b/libvips/format/format.c @@ -41,6 +41,17 @@ #include #endif /*WITH_DMALLOC*/ +/** + * SECTION: VipsFormat + * @short_description: load and save in a variety of formats + * @stability: Stable + * @see_also: image + * @include: vips/vips.h + * + * VIPS has a simple system for representing image loader + * + */ + /* To iterate over supported formats, we build a temp list of subclasses of * VipsFormat, sort by priority, iterate, and free. */ diff --git a/libvips/include/vips/image.h b/libvips/include/vips/image.h index 88805daa..5a4a6404 100644 --- a/libvips/include/vips/image.h +++ b/libvips/include/vips/image.h @@ -198,6 +198,12 @@ typedef struct _VipsImage { /* Parent/child relationships, built from args to im_demand_hint(). * We use these to invalidate pixel buffers on im_invalidate(). Use * 'serial' to spot circular dependencies. + * + * Parents are later in the tree, so it's child1 + child2 -> parent, + * for example. On im_invalidate(), we dispose the caches on all + * parents of an image. + * + * See also hint_set below. */ GSList *parents; GSList *children; @@ -223,6 +229,14 @@ typedef struct _VipsImage { * been truncated. */ size_t file_length; + + /* Set this when im_demand_hint_array() is called, and check in any + * operation that will demand pixels from the image. + * + * We use im_demand_hint_array() to build the tree of parent/child + * relationships, so it's a mandatory thing. + */ + gboolean hint_set; } VipsImage; /* Pixel address calculation macros. diff --git a/libvips/include/vips/region.h b/libvips/include/vips/region.h index 61f7d6d9..6c3da04f 100644 --- a/libvips/include/vips/region.h +++ b/libvips/include/vips/region.h @@ -81,9 +81,9 @@ int im_region_position( REGION *reg1, int x, int y ); int im_prepare( REGION *reg, Rect *r ); int im_prepare_to( REGION *reg, REGION *dest, Rect *r, int x, int y ); -typedef void *(*im_start_fn)( IMAGE *, void *, void * ); -typedef int (*im_generate_fn)( REGION *, void *, void *, void *); -typedef int (*im_stop_fn)( void *, void *, void * ); +typedef void *(*im_start_fn)( IMAGE *out, void *a, void *b ); +typedef int (*im_generate_fn)( REGION *out, void *seq, void *a, void *b ); +typedef int (*im_stop_fn)( void *seq, void *a, void *b ); void *im_start_one( IMAGE *out, void *in, void *dummy ); int im_stop_one( void *seq, void *dummy1, void *dummy2 ); @@ -101,12 +101,9 @@ int im_iterate( IMAGE *im, void *a, void *b ); +int im_demand_hint_array( IMAGE *im, im_demand_type hint, IMAGE **in ); int im_demand_hint( IMAGE *im, im_demand_type hint, ... ) __attribute__((sentinel)); -int im_demand_hint_array( IMAGE *im, im_demand_type hint, IMAGE **in ); - -void im_free_region_array( REGION **regs ); -REGION **im_allocate_region_array( IMAGE *im, int count ); /* Buffer processing. */ diff --git a/libvips/iofuncs/Makefile.am b/libvips/iofuncs/Makefile.am index 9ed9176f..1a5649a2 100644 --- a/libvips/iofuncs/Makefile.am +++ b/libvips/iofuncs/Makefile.am @@ -35,7 +35,6 @@ libiofuncs_la_SOURCES = \ im_guess_prefix.c \ im_wbuffer.c \ im_wrapmany.c \ - im_wraptwo.c \ im_writeline.c \ memory.c \ package.c \ diff --git a/libvips/iofuncs/im_demand_hint.c b/libvips/iofuncs/im_demand_hint.c index ab901d6c..29ae7029 100644 --- a/libvips/iofuncs/im_demand_hint.c +++ b/libvips/iofuncs/im_demand_hint.c @@ -1,54 +1,4 @@ -/* @(#) Hint to the evaluation mechanism that it should ask for output from - * @(#) this image with a certain shape of patch. - * @(#) - * @(#) int - * @(#) im_demand_hint( im, hint, in1, in2, ..., NULL ) - * @(#) IMAGE *im, *in1, *in2, ...; - * @(#) im_demand_type hint; - * @(#) - * @(#) hint may be one of - * @(#) - * @(#) IM_THINSTRIP - * @(#) This operation would like to output strips the width of the - * @(#) image and a few pels high. This is option suitable for - * @(#) point-to-point operations, such as those in the arithmetic - * @(#) package. - * @(#) - * @(#) This is the fastest style for most simple operations. - * @(#) - * @(#) IM_FATSTRIP - * @(#) This operation would like to output strips the width of the - * @(#) image and as high as possible. This option is suitable for - * @(#) area operations which do not violently transform coordinates, - * @(#) such as im_conv(). - * @(#) - * @(#) IM_SMALLTILE - * @(#) This is the most general demand format, and is the default. - * @(#) Output is demanded in small (around 100x100 pel) sections. - * @(#) This style works reasonably efficiently, even for bizzare - * @(#) operations like 45 degree rotate. - * @(#) - * @(#) IM_ANY - * @(#) Not from a disc file, so any geometry is OK. - * @(#) - * @(#) NOTE: demand style falls back to the most restrictive in the pipeline. - * @(#) All pipeline elements in the pipeline must agree on IM_THINSTRIP - * @(#) before output will be asked for in this manner. If you do not set a - * @(#) hint, you will get IM_SMALLTILE. - * @(#) - * @(#) in1, in2, ... are the images on which out will make demands. You - * @(#) should terminate the list with NULL. - * @(#) - * @(#) int - * @(#) im_demand_hint_array( im, hint, in ) - * @(#) IMAGE *im, **in; - * @(#) im_demand_type hint; - * @(#) - * @(#) As above, but in is a NULL-terminated array of input images. Use - * @(#) im_allocate_input_array() to build the input array. - * @(#) - * @(#) Returns non-zero on failure. - * @(#) +/* demand hints * * Copyright: The National Gallery, 1993 * Written on: 6/9/93 @@ -60,6 +10,8 @@ * fails for image import * 1/12/06 * - build parent/child links as well + * 8/10/09 + * - gtkdoc comments */ /* @@ -120,10 +72,28 @@ find_least( im_demand_type a, im_demand_type b ) return( (im_demand_type) IM_MIN( (int) a, (int) b ) ); } -/* Set hint for this image. +/** + * im_demand_hint_array: + * @im: image to set hint for + * @hint: hint for this image + * @in: array of input images to this operation + * + * Operations can set demand hints, that is, hints to the VIPS IO system about + * the type of region geometry this operation works best with. For example, + * operations which transform coordinates will usually work best with + * %IM_SMALLTILE, operations which work on local windows of pixels will like + * %IM_FATSTRIP. + * + * VIPS uses the list of input images to build the tree of operations it needs + * for the cache invalidation system. You have to call this function, or its + * varargs friend im_demand_hint(). + * + * Returns: 0 on success, or -1 on error. + * + * See also: im_demand_hint(), im_generate(). */ int -im_demand_hint_array( IMAGE *im, im_demand_type hint, IMAGE **in ) +im_demand_hint_array( IMAGE *im, VipsDemandStyle hint, IMAGE **in ) { int i, len, nany; @@ -163,13 +133,28 @@ im_demand_hint_array( IMAGE *im, im_demand_type hint, IMAGE **in ) for( i = 0; i < len; i++ ) im__link_make( im, in[i] ); + /* Set a flag on the image to say we remember to call this thing. + * im_generate() and friends check this. + */ + im->hint_set = TRUE; + return( 0 ); } -/* Build an array, and call the above. +/** + * im_demand_hint: + * @im: image to set hint for + * @hint: hint for this image + * @Varargs: %NULL-terminated list of input images to this operation + * + * Build an array and call im_demand_hint_array(). + * + * Returns: 0 on success, or -1 on error. + * + * See also: im_demand_hint(), im_generate(). */ int -im_demand_hint( IMAGE *im, im_demand_type hint, ... ) +im_demand_hint( IMAGE *im, VipsDemandStyle hint, ... ) { va_list ap; int i; diff --git a/libvips/iofuncs/im_generate.c b/libvips/iofuncs/im_generate.c index 97ca0b48..da6614e5 100644 --- a/libvips/iofuncs/im_generate.c +++ b/libvips/iofuncs/im_generate.c @@ -239,6 +239,49 @@ im_allocate_input_array( IMAGE *out, ... ) return( ar ); } +/** + * im_start_fn: + * @out: image being calculated + * @a: user data + * @b: user data + * + * Start a new processing sequence for this generate function. This allocates + * per-thread state, such as an input region. + * + * See also: im_start_one(), im_start_many(). + * + * Returns: a new sequence value + */ + +/** + * im_generate_fn: + * @out: #REGION to fill + * @seq: sequence value + * @a: user data + * @b: user data + * + * Fill @out->valid with pixels. @seq contains per-thread state, such as the + * input regions. + * + * See also: im_generate(), im_stop_many(). + * + * Returns: 0 on success, -1 on error. + */ + +/** + * im_stop_fn: + * @seq: sequence value + * @a: user data + * @b: user data + * + * Stop a processing sequence. This frees + * per-thread state, such as an input region. + * + * See also: im_stop_one(), im_stop_many(). + * + * Returns: 0 on success, -1 on error. + */ + /* Loop over a big region, filling it in many small pieces with threads. */ static int @@ -437,6 +480,12 @@ im_generate( IMAGE *im, g_assert( !im_image_sanity( im ) ); + if( !im->hint_set ) { + im_error( "im_generate", + "%s", _( "im_demand_hint() not set" ) ); + return( -1 ); + } + if( im->Xsize <= 0 || im->Ysize <= 0 || im->Bands <= 0 ) { im_error( "im_generate", "%s", _( "bad dimensions" ) ); diff --git a/libvips/iofuncs/im_init.c b/libvips/iofuncs/im_init.c index b181e8d9..3c8d568e 100644 --- a/libvips/iofuncs/im_init.c +++ b/libvips/iofuncs/im_init.c @@ -33,6 +33,8 @@ * - lock global image list (thanks lee) * 19/3/09 * - add file_length + * 8/10/09 + * - add set_hint */ /* @@ -172,6 +174,8 @@ im_init( const char *filename ) im->file_length = 0; + im->hint_set = FALSE; + if( !(im->filename = im_strdup( NULL, filename )) ) { im_close( im ); return( NULL ); diff --git a/libvips/iofuncs/im_iterate.c b/libvips/iofuncs/im_iterate.c index 08013b19..a5ef0df8 100644 --- a/libvips/iofuncs/im_iterate.c +++ b/libvips/iofuncs/im_iterate.c @@ -193,7 +193,22 @@ iterate( im_threadgroup_t *tg, IMAGE *im, return( res ); } -/* Scan region over image in small pieces. +/** + * im_iterate: + * @im: scan over this image + * @start: start sequences with this function + * @generate: generate pixels with this function + * @stop: stop sequences with this function + * @a: user data + * @b: user data + * + * Loops over an image. @generate is called for every pixel in the image, with + * the @reg argument being a region of pixels for processing. im_iterate() is + * used to implement operations like im_avg() which have no image output. + * + * See also: im_generate(), im_open(). + * + * Returns: 0 on success, or -1 on error. */ int im_iterate( IMAGE *im, diff --git a/libvips/iofuncs/im_prepare.c b/libvips/iofuncs/im_prepare.c index b812ff0f..8050eb1b 100644 --- a/libvips/iofuncs/im_prepare.c +++ b/libvips/iofuncs/im_prepare.c @@ -270,7 +270,8 @@ im_prepare_to_generate( REGION *reg, REGION *dest, Rect *r, int x, int y ) return( 0 ); } -/** im_prepare_to: +/** + * im_prepare_to: * @reg: region to prepare * @dest: region to write to * @r: #Rect of pixels you need to be able to address diff --git a/libvips/iofuncs/im_wrapmany.c b/libvips/iofuncs/im_wrapmany.c index f250a5f0..74452ef2 100644 --- a/libvips/iofuncs/im_wrapmany.c +++ b/libvips/iofuncs/im_wrapmany.c @@ -1,20 +1,4 @@ -/* Wrap-up a buffer processing function as a PIO VIPS function. - * - * Given a NULL-terminated list of input images all of the same size, an - * output image and a buffer processing function, make a PIO image processing - * operation. - * - * int im_wrapmany( IMAGE **in, IMAGE *out, - * im_wrapmany_fn fn, void *a, void *b ) - * - * where im_wrapmany_fn has type: - * - * process_buffer( void **in, void *out, int n, - * void *a, void *b ) - * - * in is a NULL-terminated array of input buffers, out is an output buffer, n - * is the number of pixels (note! not band-elements) and a and b are extra - * arguments carried for the function +/* wrapmany * * Modified: * 1/8/95 JC @@ -24,6 +8,9 @@ * - amazing error ... only worked if ir and or had same valid * 23/1/08 * - do im_wrapone() in terms of this + * 8/10/09 + * - gtkdoc comments + * - move im_wraptwo in here */ /* @@ -150,7 +137,34 @@ dupims( IMAGE *out, IMAGE **in ) return( new ); } -/* Wrap up as a partial. +/** + * im_wrapmany_fn: + * @in: %NULL-terminated array of input buffers + * @out: write processed pixels here + * @width: number of pixels in buffer + * @a: user data + * @b: user data + * + * Given an array of buffers of input pixels, write a buffer of output pixels. + */ + +/** + * im_wrapmany: + * @in: %NULL-terminated array of input images + * @out: image to generate + * @fn: buffer-processing function + * @a: user data + * @b: user data + * + * Wrap-up a buffer processing function as a PIO VIPS function. + * + * Given a NULL-terminated list of input images all of the same size, an + * output image and a buffer processing function, make a PIO image processing + * operation. + * + * See also: im_wrapone(), im_wraptwo(), im_generate(). + * + * Returns: 0 on success, or -1 on error. */ int im_wrapmany( IMAGE **in, IMAGE *out, im_wrapmany_fn fn, void *a, void *b ) @@ -212,6 +226,35 @@ wrapone_gen( void **ins, void *out, int width, Bundle *bun, void *dummy ) ((im_wrapone_fn) (bun->fn)) (ins[0], out, width, bun->a, bun->b ); } +/** + * im_wrapone_fn: + * @in: input pixels + * @out: write processed pixels here + * @width: number of pixels in buffer + * @a: user data + * @b: user data + * + * Given a buffer of input pixels, write a buffer of output pixels. + */ + +/** + * im_wrapone: + * @in: input image + * @out: image to generate + * @fn: buffer-processing function + * @a: user data + * @b: user data + * + * Wrap-up a buffer processing function as a PIO VIPS function. + * + * Given an input image, an + * output image and a buffer processing function, make a PIO image processing + * operation. + * + * See also: im_wrapmany(), im_wraptwo(), im_generate(). + * + * Returns: 0 on success, or -1 on error. + */ int im_wrapone( IMAGE *in, IMAGE *out, im_wrapone_fn fn, void *a, void *b ) { @@ -229,17 +272,44 @@ im_wrapone( IMAGE *in, IMAGE *out, im_wrapone_fn fn, void *a, void *b ) (im_wrapmany_fn) wrapone_gen, bun, NULL ) ); } -/* - - commented out for now ... replace im_wraptwo with this? - static void wraptwo_gen( void **ins, void *out, int width, Bundle *bun, void *dummy ) { - ((im_wraptwo_fn) (bun->fn)) (ins[0], ins[1], or, + ((im_wraptwo_fn) (bun->fn)) (ins[0], ins[1], out, width, bun->a, bun->b ); } +/** + * im_wraptwo_fn: + * @in1: input pixels from image 1 + * @in2: input pixels from image 2 + * @out: write processed pixels here + * @width: number of pixels in buffer + * @a: user data + * @b: user data + * + * Given a pair of buffers of input pixels, write a buffer of output pixels. + */ + +/** + * im_wraptwo: + * @in1: first input image + * @in2: second input image + * @out: image to generate + * @fn: buffer-processing function + * @a: user data + * @b: user data + * + * Wrap-up a buffer processing function as a PIO VIPS function. + * + * Given a pair of input images of the same size, an + * output image and a buffer processing function, make a PIO image processing + * operation. + * + * See also: im_wrapone(), im_wrapmany(), im_generate(). + * + * Returns: 0 on success, or -1 on error. + */ int im_wraptwo( IMAGE *in1, IMAGE *in2, IMAGE *out, im_wraptwo_fn fn, void *a, void *b ) @@ -255,5 +325,3 @@ im_wraptwo( IMAGE *in1, IMAGE *in2, IMAGE *out, return( im_wrapmany( invec, out, (im_wrapmany_fn) wraptwo_gen, bun, NULL ) ); } - - */ diff --git a/libvips/iofuncs/im_wraptwo.c b/libvips/iofuncs/im_wraptwo.c deleted file mode 100644 index df4166e8..00000000 --- a/libvips/iofuncs/im_wraptwo.c +++ /dev/null @@ -1,103 +0,0 @@ -/* As im_wrapmany, but just allow one input and one output. - * - * The types become: - * - * int im_wrapone( IMAGE *in, IMAGE *out, - * im_wrapone_fn fn, void *a, void *b ) - * - * where im_wrapone_fn has type: - * - * process_buffer( void *in, void *out, int n, - * void *a, void *b ) - * 28/7/97 JC - * - amazing error ... failed if or and ir were different sizes - */ - -/* - - This file is part of VIPS. - - VIPS is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include -#include - -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -typedef struct { - im_wraptwo_fn fn; /* Function we call */ - void *a, *b; /* User values for function */ -} UserBundle; - -/* Build or->valid a line at a time from ir. - */ -static int -process_region( REGION *or, void *seq, void *unrequired, void *b ) -{ - if( im_prepare_many( (REGION**)seq, & or-> valid )) - return -1; - { - void *out= IM_REGION_ADDR_TOPLEFT( or ); - void *in1= IM_REGION_ADDR( ((REGION**)seq)[0], or-> valid. left, or-> valid. top ); - void *in2= IM_REGION_ADDR( ((REGION**)seq)[1], or-> valid. left, or-> valid. top ); - size_t out_skip= IM_REGION_LSKIP( or ); - size_t in1_skip= IM_REGION_LSKIP( ((REGION**)seq)[0] ); - size_t in2_skip= IM_REGION_LSKIP( ((REGION**)seq)[1] ); - void *out_stop= out + out_skip * or-> valid. height; - - for( ; out < out_stop; out+= out_skip, in1+= in1_skip, in2+= in2_skip ) - ((UserBundle*) b)-> fn( in1, in2, out, or-> valid. width, ((UserBundle*) b)-> a, ((UserBundle*) b)-> b ); - - return 0; - } -} - -/* Wrap up as a partial. - */ -int -im_wraptwo( IMAGE *in1, IMAGE *in2, IMAGE *out, im_wraptwo_fn fn, void *a, void *b ) -{ - if( im_pincheck( in1 ) || im_pincheck( in2 ) || im_poutcheck( out )) - return -1; - { - UserBundle *bun= IM_NEW( out, UserBundle ); - IMAGE **ins= im_allocate_input_array( out, in1, in2, NULL ); - - if( ! bun || ! ins ) - return -1; - - bun-> fn= fn; - bun-> a= a; - bun-> b= b; - - return im_demand_hint( out, IM_THINSTRIP, in1, in2, NULL ) - || im_generate( out, im_start_many, process_region, im_stop_many, (void*) ins, (void*) bun ); - } -}