This commit is contained in:
John Cupitt 2009-10-08 14:02:38 +00:00
parent cc68842434
commit a584569881
14 changed files with 242 additions and 198 deletions

View File

@ -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

9
TODO
View File

@ -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()?

View File

@ -22,6 +22,7 @@
<xi:include href="xml/callback.xml"/>
<xi:include href="xml/error.xml"/>
<xi:include href="xml/meta.xml"/>
<xi:include href="xml/region.xml"/>
<xi:include href="xml/buf.xml"/>
</chapter>
@ -39,7 +40,6 @@
<xi:include href="xml/object.xml"/>
<xi:include href="xml/proto.xml"/>
<xi:include href="xml/colour.xml"/>
<xi:include href="xml/region.xml"/>
<xi:include href="xml/transform.xml"/>
<xi:include href="xml/util.xml"/>
<xi:include href="xml/threadgroup.xml"/>

View File

@ -41,6 +41,17 @@
#include <dmalloc.h>
#endif /*WITH_DMALLOC*/
/**
* SECTION: VipsFormat
* @short_description: load and save in a variety of formats
* @stability: Stable
* @see_also: <link linkend="libvips-image">image</link>
* @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.
*/

View File

@ -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.

View File

@ -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.
*/

View File

@ -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 \

View File

@ -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;

View File

@ -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" ) );

View File

@ -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 );

View File

@ -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,

View File

@ -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

View File

@ -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 ) );
}
*/

View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdlib.h>
#include <vips/vips.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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 );
}
}