Merge remote-tracking branch 'origin/rot45'

This commit is contained in:
John Cupitt 2013-10-29 10:14:34 +00:00
commit 7dfab19bb0
113 changed files with 2814 additions and 1948 deletions

View File

@ -1,3 +1,15 @@
19/10/13 started 7.37.0
- redone im_rotate_*mask45(), im_gauss_*mask*(), im_log_*mask(), im_dilate(),
im_erode(), im_rank_image(), im_compass(), im_linedet(), im_gradient(),
im_convsep(), im_convsep_f() as classes
- vips_init() now does some ABI compat checking, though this change requires
an ABI break
- add "interlace" option to vips_jpegsave()
- remove vips_image_copy_fields() and vips_demand_hint() and add
vips_image_pipeline() to do both jobs
- vipsthumbnail allows non-square bounding boxes, thanks seth
- add vips_matrixprint()
18/10/13 started 7.36.3
- fix compiler warnings in ubuntu 13.10
- reverse similarity rotation direction to match the convention used

39
TODO
View File

@ -1,20 +1,9 @@
Next version
============
- make vips_init() into a macro, check sizes of important structs against size
at library compile time
add a new API call like vips__get_sizeof_image() which returns
sizeof(VipsImage) from library compile time, compare that to the application
compile-time value
vips_init() macro then passes control on to vips__init() for real startup
breaks binary API sadly
- do conv and morph quickly as simple wrappers over the vips7 operations
- add vips_gaussian_blur() with approx / int / float precision, maybe
vips_resize() as well?
- do much fancier profiling with timing on all locks saved in memory and
dumped on exit
@ -23,16 +12,6 @@ Next version
- use g_log() instead of vips_info()
- do we always call copy_fields and demand_hint with ALL input images? what
about the operators in conversion?
could we add something to check that the two calls agree on the image lists?
I think they should
- support multiscan jpeg write? see
https://github.com/jcupitt/ruby-vips/issues/41
- object construction is threadsafe, but class construction is not
https://github.com/jcupitt/libvips/issues/64
@ -157,6 +136,18 @@ convolution
wait for vipsobject for this
- we have aconv and aconvsep
test timing, make sure it;s worth having a separate aconvsep version
if it is, make im_aconvsep an optimisation: call im_aconvsep_raw() from
vips_conv() if mask width or height == 1 and prec == APPROX
now we can get rid of im_aconvsep() since it's just vips_convsep() with prec
set to approx
aconv needs some more work, get it going at least with gaussian
arithmetic
==========

View File

@ -2,7 +2,7 @@
# also update the version number in the m4 macros below
AC_INIT([vips], [7.36.3], [vipsip@jiscmail.ac.uk])
AC_INIT([vips], [7.37.0], [vipsip@jiscmail.ac.uk])
# required for gobject-introspection
AC_PREREQ(2.62)
@ -16,8 +16,8 @@ AC_CONFIG_MACRO_DIR([m4])
# user-visible library versioning
m4_define([vips_major_version], [7])
m4_define([vips_minor_version], [36])
m4_define([vips_micro_version], [3])
m4_define([vips_minor_version], [37])
m4_define([vips_micro_version], [0])
m4_define([vips_version],
[vips_major_version.vips_minor_version.vips_micro_version])
@ -36,9 +36,9 @@ VIPS_VERSION_STRING=$VIPS_VERSION-`date`
# binary interface changes backwards compatible?: increment age
# binary interface changes not backwards compatible?: reset age to 0
LIBRARY_CURRENT=35
LIBRARY_REVISION=3
LIBRARY_AGE=0
LIBRARY_CURRENT=36
LIBRARY_REVISION=0
LIBRARY_AGE=1
# patched into include/vips/version.h
AC_SUBST(VIPS_VERSION)

View File

@ -545,11 +545,9 @@ vips_arithmetic_build( VipsObject *object )
*/
arithmetic->ready = size;
if( vips_image_copy_fields_array( arithmetic->out,
arithmetic->ready ) )
if( vips_image_pipeline_array( arithmetic->out,
VIPS_DEMAND_STYLE_THINSTRIP, arithmetic->ready ) )
return( -1 );
vips_demand_hint_array( arithmetic->out,
VIPS_DEMAND_STYLE_THINSTRIP, arithmetic->ready );
arithmetic->out->Bands = arithmetic->ready[0]->Bands;
arithmetic->out->BandFmt =

View File

@ -150,7 +150,8 @@ vips_hist_find_build( VipsObject *object )
/* Make the output image.
*/
if( vips_image_copy_fields( hist_find->out, statistic->ready ) )
if( vips_image_pipelinev( hist_find->out,
VIPS_DEMAND_STYLE_ANY, statistic->ready, NULL ) )
return( -1 );
vips_image_init_fields( hist_find->out,
hist_find->hist->mx + 1, 1, hist_find->hist->bands,

View File

@ -163,7 +163,8 @@ vips_hist_find_indexed_build( VipsObject *object )
VIPS_UNREF( indexed->hist->reg );
if( vips_image_copy_fieldsv( indexed->out,
if( vips_image_pipelinev( indexed->out,
VIPS_DEMAND_STYLE_ANY,
statistic->ready, indexed->index_ready, NULL ) )
return( -1 );
vips_image_init_fields( indexed->out,

View File

@ -154,7 +154,8 @@ vips_hist_find_ndim_build( VipsObject *object )
build( object ) )
return( -1 );
if( vips_image_copy_fields( ndim->out, statistic->ready ) )
if( vips_image_pipelinev( ndim->out,
VIPS_DEMAND_STYLE_ANY, statistic->ready, NULL ) )
return( -1 );
vips_image_init_fields( ndim->out,
ndim->bins,

View File

@ -136,8 +136,10 @@ vips_profile_build( VipsObject *object )
/* Make the output image.
*/
if( vips_image_copy_fields( profile->columns, statistic->ready ) ||
vips_image_copy_fields( profile->rows, statistic->ready ) )
if( vips_image_pipelinev( profile->columns,
VIPS_DEMAND_STYLE_ANY, statistic->ready, NULL ) ||
vips_image_pipelinev( profile->rows,
VIPS_DEMAND_STYLE_ANY, statistic->ready, NULL ) )
return( -1 );
profile->columns->Ysize = 1;
profile->columns->BandFmt = VIPS_FORMAT_INT;

View File

@ -141,8 +141,10 @@ vips_project_build( VipsObject *object )
/* Make the output image.
*/
if( vips_image_copy_fields( project->columns, statistic->ready ) ||
vips_image_copy_fields( project->rows, statistic->ready ) )
if( vips_image_pipelinev( project->columns,
VIPS_DEMAND_STYLE_ANY, statistic->ready, NULL ) ||
vips_image_pipelinev( project->rows,
VIPS_DEMAND_STYLE_ANY, statistic->ready, NULL ) )
return( -1 );
project->columns->Ysize = 1;
project->columns->BandFmt =

View File

@ -320,10 +320,9 @@ vips_colour_build( VipsObject *object )
*/
g_assert( !colour->in[colour->n] );
if( vips_image_copy_fields_array( colour->out, colour->in ) )
if( vips_image_pipeline_array( colour->out,
VIPS_DEMAND_STYLE_THINSTRIP, colour->in ) )
return( -1 );
vips_demand_hint_array( colour->out,
VIPS_DEMAND_STYLE_THINSTRIP, colour->in );
colour->out->Coding = colour->coding;
colour->out->Type = colour->interpretation;
colour->out->BandFmt = colour->format;

View File

@ -17,12 +17,14 @@ libconversion_la_SOURCES = \
replicate.c \
cast.c \
bandjoin.c \
bandrank.c \
recomb.c \
bandmean.c \
bandbool.c \
bandary.h \
bandary.c \
rot.c \
rot45.c \
ifthenelse.c \
falsecolour.c \
msb.c \

View File

@ -147,10 +147,9 @@ vips_bandary_build( VipsObject *object )
return( -1 );
bandary->ready = size;
if( vips_image_copy_fields_array( conversion->out, bandary->ready ) )
if( vips_image_pipeline_array( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, bandary->ready ) )
return( -1 );
vips_demand_hint_array( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, bandary->ready );
conversion->out->Bands = bandary->out_bands;

View File

@ -0,0 +1,322 @@
/* Sort a set of images, pixelwise, and pick out the index at each point.
*
* 19/8/03
* - from im_maxvalue(), via im_gbandrank()
* 10/11/10
* - gtkdoc
* - cleanups
* - any mix of formats and bands
* 23/10/13
* - redo as a class, from bandrank.c
*/
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
/*
#define VIPS_DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include <vips/debug.h>
#include "bandary.h"
typedef struct _VipsBandrank {
VipsBandary parent_instance;
/* The input images.
*/
VipsArea *in;
int index; /* Pick out this one */
} VipsBandrank;
typedef VipsBandaryClass VipsBandrankClass;
G_DEFINE_TYPE( VipsBandrank, vips_bandrank, VIPS_TYPE_BANDARY );
/* Special-case max and min (rather common).
*/
#define FIND_MAX( TYPE ) { \
for( x = 0; x < sz; x++ ) { \
TYPE top = ((TYPE *) p[0])[x]; \
\
for( i = 1; i < bandary->n; i++ ) { \
TYPE v = ((TYPE *) p[i])[x]; \
\
if( v > top ) \
top = v; \
} \
\
((TYPE *) q)[x] = top; \
} \
}
#define FIND_MIN( TYPE ) { \
for( x = 0; x < sz; x++ ) { \
TYPE bot = ((TYPE *) p[0])[x]; \
\
for( i = 1; i < bandary->n; i++ ) { \
TYPE v = ((TYPE *) p[i])[x]; \
\
if( v < bot ) \
bot = v; \
} \
\
((TYPE *) q)[x] = bot; \
} \
}
#define FIND_RANK( TYPE ) { \
TYPE *sort = (TYPE *) sort_buffer; \
\
for( x = 0; x < sz; x++ ) { \
for( i = 0; i < bandary->n; i++ ) { \
TYPE v = ((TYPE *) p[i])[x]; \
\
/* Search for element >v.
*/\
for( j = 0; j < i; j++ ) \
if( sort[j] > v ) \
break; \
\
/* Move remaining elements down.
*/ \
for( k = i; k > j; k-- ) \
sort[k] = sort[k - 1]; \
\
/* Insert this element.
*/ \
sort[j] = v; \
} \
\
((TYPE *) q)[x] = sort[bandrank->index]; \
} \
}
#define SWITCH( OPERATION ) \
switch( in[0]->BandFmt ) { \
case VIPS_FORMAT_UCHAR: OPERATION( unsigned char ); break; \
case VIPS_FORMAT_CHAR: OPERATION( signed char ); break; \
case VIPS_FORMAT_USHORT: OPERATION( unsigned short ); break; \
case VIPS_FORMAT_SHORT: OPERATION( signed short ); break; \
case VIPS_FORMAT_UINT: OPERATION( unsigned int ); break; \
case VIPS_FORMAT_INT: OPERATION( signed int ); break; \
case VIPS_FORMAT_FLOAT: OPERATION( float ); break; \
case VIPS_FORMAT_DOUBLE: OPERATION( double ); break; \
\
default: \
g_assert( 0 ); \
}
/* Sort input band elements in the stack. Needs to be big enough for
* sizeof(band-element) * number-of-images.
*/
#define SORT_BUFFER (1024)
static void
vips_bandrank_buffer( VipsBandary *bandary, VipsPel *q, VipsPel **p, int width )
{
VipsBandrank *bandrank = (VipsBandrank *) bandary;
VipsImage **in = bandary->ready;
int sz = width * in[0]->Bands;
int i, j, k;
int x;
VipsPel sort_buffer[SORT_BUFFER];
/* Special-case max and min.
*/
if( bandrank->index == 0 )
SWITCH( FIND_MIN )
else if( bandrank->index == bandary->n - 1 )
SWITCH( FIND_MAX )
else
SWITCH( FIND_RANK )
}
static int
vips_bandrank_build( VipsObject *object )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsBandary *bandary = (VipsBandary *) object;
VipsBandrank *bandrank = (VipsBandrank *) object;
if( bandrank->in ) {
VipsImage **band = (VipsImage **)
vips_object_local_array( object, bandrank->in->n );
if( bandrank->in->n == 1 )
return( vips_bandary_copy( bandary ) );
/* We need to keep one band element for every input image
* on the stack.
*/
if( sizeof( double ) * bandrank->in->n > SORT_BUFFER ) {
vips_error( class->nickname,
"%s", _( "too many input images" ) );
return( -1 );
}
if( vips__bandalike_vec( class->nickname,
bandrank->in->data, band, bandrank->in->n, 0 ) )
return( -1 );
bandary->in = band;
bandary->n = bandrank->in->n;
bandary->out_bands = band[0]->Bands;
if( bandrank->index == -1 )
bandrank->index = bandary->n / 2;
}
if( VIPS_OBJECT_CLASS( vips_bandrank_parent_class )->build( object ) )
return( -1 );
return( 0 );
}
static void
vips_bandrank_class_init( VipsBandrankClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
VipsBandaryClass *bandary_class = VIPS_BANDARY_CLASS( class );
VIPS_DEBUG_MSG( "vips_bandrank_class_init\n" );
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
vobject_class->nickname = "bandrank";
vobject_class->description = _( "band-wise rank of a set of images" );
vobject_class->build = vips_bandrank_build;
bandary_class->process_line = vips_bandrank_buffer;
VIPS_ARG_BOXED( class, "in", 0,
_( "Input" ),
_( "Array of input images" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsBandrank, in ),
VIPS_TYPE_ARRAY_IMAGE );
VIPS_ARG_INT( class, "index", 0,
_( "Index" ),
_( "Select this band element from sorted list" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsBandrank, index ),
-1, 1000000, -1 );
}
static void
vips_bandrank_init( VipsBandrank *bandrank )
{
/* -1 means median.
*/
bandrank->index = -1;
}
static int
vips_bandrankv( VipsImage **in, VipsImage **out, int n, va_list ap )
{
VipsArea *area;
VipsImage **array;
int i;
int result;
area = vips_area_new_array_object( n );
array = (VipsImage **) area->data;
for( i = 0; i < n; i++ ) {
array[i] = in[i];
g_object_ref( array[i] );
}
result = vips_call_split( "bandrank", ap, area, out );
vips_area_unref( area );
return( result );
}
/**
* vips_bandrank:
* @in: array of input images
* @out: output image
* @n: number of input images
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* @index: pick this index from list of sorted values
*
* Sorts the images @in band-element-wise, then outputs an
* image in which each band element is selected from the sorted list by the
* @index parameter. For example, if @index
* is zero, then each output band element will be the minimum of all the
* corresponding input band element.
*
* By default, @index is -1, meaning pick the median value.
*
* It works for any uncoded, non-complex image type. Images are cast up to the
* smallest common-format.
*
* Any image can have either 1 band or n bands, where n is the same for all
* the non-1-band images. Single band images are then effectively copied to
* make n-band images.
*
* Smaller input images are expanded by adding black pixels.
*
* See also: vips_rank().
*
* Returns: 0 on success, -1 on error
*/
int
vips_bandrank( VipsImage **in, VipsImage **out, int n, ... )
{
va_list ap;
int result;
va_start( ap, n );
result = vips_bandrankv( in, out, n, ap );
va_end( ap );
return( result );
}

View File

@ -441,10 +441,9 @@ vips_cast_build( VipsObject *object )
vips_image_pio_input( cast->in ) )
return( -1 );
if( vips_image_copy_fields( conversion->out, cast->in ) )
if( vips_image_pipelinev( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, cast->in, NULL ) )
return( -1 );
vips_demand_hint( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, cast->in, NULL );
conversion->out->BandFmt = cast->format;

View File

@ -210,8 +210,10 @@ vips_conversion_operation_init( void )
extern GType vips_replicate_get_type( void );
extern GType vips_cast_get_type( void );
extern GType vips_bandjoin_get_type( void );
extern GType vips_bandrank_get_type( void );
extern GType vips_black_get_type( void );
extern GType vips_rot_get_type( void );
extern GType vips_rot45_get_type( void );
extern GType vips_ifthenelse_get_type( void );
extern GType vips_recomb_get_type( void );
extern GType vips_bandmean_get_type( void );
@ -245,8 +247,10 @@ vips_conversion_operation_init( void )
vips_replicate_get_type();
vips_cast_get_type();
vips_bandjoin_get_type();
vips_bandrank_get_type();
vips_black_get_type();
vips_rot_get_type();
vips_rot45_get_type();
vips_ifthenelse_get_type();
vips_recomb_get_type();
vips_bandmean_get_type();

View File

@ -250,10 +250,9 @@ vips_copy_build( VipsObject *object )
if( vips_image_pio_input( copy->in ) )
return( -1 );
if( vips_image_copy_fields( conversion->out, copy->in ) )
if( vips_image_pipelinev( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, copy->in, NULL ) )
return( -1 );
vips_demand_hint( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, copy->in, NULL );
/* Use props to adjust header fields.
*/

View File

@ -426,14 +426,12 @@ vips_embed_build( VipsObject *object )
case VIPS_EXTEND_WHITE:
case VIPS_EXTEND_BACKGROUND:
case VIPS_EXTEND_COPY:
if( vips_image_copy_fields( conversion->out, embed->in ) )
return( -1 );
/* embed is used in many places. We don't really care about
* geometry, so use ANY to avoid disturbing all pipelines.
*/
vips_demand_hint( conversion->out,
VIPS_DEMAND_STYLE_ANY, embed->in, NULL );
if( vips_image_pipelinev( conversion->out,
VIPS_DEMAND_STYLE_ANY, embed->in, NULL ) )
return( -1 );
conversion->out->Xsize = embed->width;
conversion->out->Ysize = embed->height;

View File

@ -155,10 +155,9 @@ vips_extract_area_build( VipsObject *object )
vips_check_coding_known( class->nickname, extract->in ) )
return( -1 );
if( vips_image_copy_fields( conversion->out, extract->in ) )
if( vips_image_pipelinev( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, extract->in, NULL ) )
return( -1 );
vips_demand_hint( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, extract->in, NULL );
conversion->out->Xsize = extract->width;
conversion->out->Ysize = extract->height;

View File

@ -316,10 +316,9 @@ vips_flatten_build( VipsObject *object )
vips_image_pio_input( flatten->in ) )
return( -1 );
if( vips_image_copy_fields( conversion->out, flatten->in ) )
if( vips_image_pipelinev( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, flatten->in, NULL ) )
return( -1 );
vips_demand_hint( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, flatten->in, NULL );
conversion->out->Bands -= 1;

View File

@ -198,10 +198,9 @@ vips_flip_build( VipsObject *object )
if( vips_image_pio_input( flip->in ) )
return( -1 );
if( vips_image_copy_fields( conversion->out, flip->in ) )
if( vips_image_pipelinev( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, flip->in, NULL ) )
return( -1 );
vips_demand_hint( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, flip->in, NULL );
if( flip->direction == VIPS_DIRECTION_HORIZONTAL ) {
generate_fn = vips_flip_horizontal_gen;

View File

@ -166,12 +166,11 @@ vips_grid_build( VipsObject *object )
return( -1 );
}
if( vips_image_copy_fields( conversion->out, grid->in ) )
return( -1 );
/* We can render small tiles with pointer copies.
*/
vips_demand_hint( conversion->out,
VIPS_DEMAND_STYLE_SMALLTILE, grid->in, NULL );
if( vips_image_pipelinev( conversion->out,
VIPS_DEMAND_STYLE_SMALLTILE, grid->in, NULL ) )
return( -1 );
conversion->out->Xsize = grid->in->Xsize * grid->across;
conversion->out->Ysize = grid->tile_height * grid->down;

View File

@ -442,10 +442,9 @@ vips_ifthenelse_build( VipsObject *object )
if( vips__formatalike_vec( size, format, 2 ) )
return( -1 );
if( vips_image_copy_fields_array( conversion->out, format ) )
if( vips_image_pipeline_array( conversion->out,
VIPS_DEMAND_STYLE_SMALLTILE, format ) )
return( -1 );
vips_demand_hint_array( conversion->out,
VIPS_DEMAND_STYLE_SMALLTILE, format );
if( vips_image_generate( conversion->out,
vips_start_many, generate_fn, vips_stop_many,

View File

@ -284,10 +284,9 @@ vips_insert_build( VipsObject *object )
insert->main_processed, insert->sub_processed, NULL )) )
return( -1 );
if( vips_image_copy_fields_array( conversion->out, arry ) )
if( vips_image_pipeline_array( conversion->out,
VIPS_DEMAND_STYLE_ANY, arry ) )
return( -1 );
vips_demand_hint_array( conversion->out,
VIPS_DEMAND_STYLE_ANY, arry );
/* Calculate geometry.
*/

View File

@ -201,10 +201,9 @@ vips_msb_build( VipsObject *object )
msb->in->BandFmt == VIPS_FORMAT_UCHAR )
return( vips_image_write( msb->in, conversion->out ) );
if( vips_image_copy_fields( conversion->out, msb->in ) )
if( vips_image_pipelinev( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, msb->in, NULL ) )
return( -1 );
vips_demand_hint( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, msb->in, NULL );
if( msb->band != -1 )
conversion->out->Bands = 1;

View File

@ -164,10 +164,9 @@ vips_recomb_build( VipsObject *object )
return( -1 );
recomb->coeff = t[0];
if( vips_image_copy_fields( conversion->out, recomb->in ) )
if( vips_image_pipelinev( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, recomb->in, NULL ) )
return( -1 );
vips_demand_hint( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, recomb->in, NULL );
conversion->out->Bands = recomb->m->Ysize;
if( vips_bandfmt_isint( recomb->in->BandFmt ) )

View File

@ -162,10 +162,9 @@ vips_replicate_build( VipsObject *object )
if( vips_image_pio_input( replicate->in ) )
return( -1 );
if( vips_image_copy_fields( conversion->out, replicate->in ) )
if( vips_image_pipelinev( conversion->out,
VIPS_DEMAND_STYLE_SMALLTILE, replicate->in, NULL ) )
return( -1 );
vips_demand_hint( conversion->out,
VIPS_DEMAND_STYLE_SMALLTILE, replicate->in, NULL );
conversion->out->Xsize *= replicate->across;
conversion->out->Ysize *= replicate->down;

View File

@ -1,4 +1,4 @@
/* im_rot90
/* rotate by 0/90/180/270 degrees
*
* Copyright: 1991, N. Dessipris
* Written on: 28/10/91
@ -294,13 +294,16 @@ vips_rot_build( VipsObject *object )
if( vips_image_pio_input( rot->in ) )
return( -1 );
if( vips_image_copy_fields( conversion->out, rot->in ) )
hint = rot->angle == VIPS_ANGLE_180 ?
VIPS_DEMAND_STYLE_THINSTRIP :
VIPS_DEMAND_STYLE_SMALLTILE;
if( vips_image_pipelinev( conversion->out, hint, rot->in, NULL ) )
return( -1 );
switch( rot->angle ) {
case VIPS_ANGLE_90:
generate_fn = vips_rot90_gen;
hint = VIPS_DEMAND_STYLE_SMALLTILE;
conversion->out->Xsize = rot->in->Ysize;
conversion->out->Ysize = rot->in->Xsize;
conversion->out->Xoffset = rot->in->Ysize;
@ -309,14 +312,12 @@ vips_rot_build( VipsObject *object )
case VIPS_ANGLE_180:
generate_fn = vips_rot180_gen;
hint = VIPS_DEMAND_STYLE_THINSTRIP;
conversion->out->Xoffset = rot->in->Xsize;
conversion->out->Yoffset = rot->in->Ysize;
break;
case VIPS_ANGLE_270:
generate_fn = vips_rot270_gen;
hint = VIPS_DEMAND_STYLE_SMALLTILE;
conversion->out->Xsize = rot->in->Ysize;
conversion->out->Ysize = rot->in->Xsize;
conversion->out->Xoffset = 0;
@ -331,8 +332,6 @@ vips_rot_build( VipsObject *object )
return( 0 );
}
vips_demand_hint( conversion->out, hint, rot->in, NULL );
if( vips_image_generate( conversion->out,
vips_start_one, generate_fn, vips_stop_one,
rot->in, rot ) )

319
libvips/conversion/rot45.c Normal file
View File

@ -0,0 +1,319 @@
/* 'lossless' 45 degree rotate ... odd-sized square images only
*
* Author: N. Dessipris (Copyright, N. Dessipris 1991)
* Written on: 08/05/1991
* Modified on: 28/05/1991
* 12/10/95 JC
* - small revisions, needs rewriting really
* 7/8/96 JC
* - absolutely foul desp code revised
* - many bugs and mem leaks fixed
* 1/3/99 JC
* - oops, fns were not preserving scale and offset
* 1/12/10
* - allow any size mask for the 90 degree rot45ates by using im_rot4590().
* 12/10/13
* - rewritten as a class
*/
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
/*
#define VIPS_DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include <vips/debug.h>
#include "pconversion.h"
typedef struct _VipsRot45 {
VipsConversion parent_instance;
/* The input image.
*/
VipsImage *in;
/* Rotate by ...
*/
VipsAngle45 angle;
} VipsRot45;
typedef VipsConversionClass VipsRot45Class;
G_DEFINE_TYPE( VipsRot45, vips_rot45, VIPS_TYPE_CONVERSION );
#define COPY( Q, P ) { \
VipsPel *q = (Q); \
VipsPel *p = (P); \
int b;\
\
for( b = 0; b < ps; b++ )\
q[b] = p[b];\
}
#define ASSIGN( Xout, Yout, Xin, Yin ) \
COPY( VIPS_IMAGE_ADDR( out, Xout, Yout ), \
VIPS_IMAGE_ADDR( in, Xin, Yin ) )
#define POINT_TO_TEMP( q, Xin, Yin ) \
COPY( q, VIPS_IMAGE_ADDR( in, Xin, Yin ) )
#define TEMP_TO_POINT( Xout, Yout, p ) \
COPY( VIPS_IMAGE_ADDR( out, Xout, Yout ), p )
/* This can work inplace, ie. in == out is allowed.
*/
static void
vips_rot45_rot45( VipsImage *out, VipsImage *in )
{
size_t ps = VIPS_IMAGE_SIZEOF_PEL( in );
VipsPel *temp = VIPS_ARRAY( in, ps, VipsPel );
int size = in->Xsize;
int size_2 = size / 2;
int x, y;
g_assert( in->Xsize == in->Ysize );
g_assert( out->Xsize == out->Ysize );
g_assert( in->Xsize == out->Xsize );
g_assert( in->Xsize % 2 == 1 );
/* Split the square into 8 triangles. Loop over the top-left one,
* reflect to index the others.
*
* 1 1 2 2 3
* 8 1 2 3 3
* 8 8 x 4 4
* 7 7 6 5 4
* 7 6 6 5 5
*
* do the centre separately.
*/
for( y = 0; y < size_2; y++ )
for( x = y; x < size_2; x++ ) {
/* Save 1, it goes into 2 at the end.
*/
POINT_TO_TEMP( temp, x, y );
/* Fill 1 from 8.
*/
ASSIGN( x, y,
y, size_2 - (x - y) );
/* 8 from 7.
*/
ASSIGN( y, size_2 - (x - y),
y, (size - 1) - x );
/* 7 from 6.
*/
ASSIGN( y, (size - 1) - x,
size_2 - (x - y), (size - 1) - y );
/* 6 from 5.
*/
ASSIGN( size_2 - (x - y), (size - 1) - y,
(size - 1) - x, (size - 1) - y );
/* 5 from 4.
*/
ASSIGN( (size - 1) - x, (size - 1) - y,
(size - 1) - y, (x - y) + size_2 );
/* 4 from 3.
*/
ASSIGN( (size - 1) - y, (x - y) + size_2,
(size - 1) - y, x );
/* 3 from 2.
*/
ASSIGN( (size - 1) - y, x,
(x - y) + size_2, y );
/* 2 from saved 1.
*/
TEMP_TO_POINT( (x - y) + size_2, y, temp );
}
/* Centre.
*/
ASSIGN( size_2, size_2, size_2, size_2 );
}
static int
vips_rot45_build( VipsObject *object )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsConversion *conversion = VIPS_CONVERSION( object );
VipsRot45 *rot45 = (VipsRot45 *) object;
VipsImage **t = (VipsImage **) vips_object_local_array( object, 1 );
VipsImage *from;
if( VIPS_OBJECT_CLASS( vips_rot45_parent_class )->build( object ) )
return( -1 );
if( vips_check_oddsquare( class->nickname, rot45->in ) )
return( -1 );
if( rot45->angle == VIPS_ANGLE45_0 )
return( vips_image_write( rot45->in, conversion->out ) );
if( vips_image_wio_input( rot45->in ) )
return( -1 );
t[0] = vips_image_new_buffer();
if( vips_image_pipelinev( t[0],
VIPS_DEMAND_STYLE_ANY, rot45->in, NULL ) )
return( -1 );
if( vips_image_write_prepare( t[0] ) )
return( -1 );
from = rot45->in;
switch( rot45->angle ) {
case VIPS_ANGLE45_315:
vips_rot45_rot45( t[0], from );
from = t[0];
case VIPS_ANGLE45_270:
vips_rot45_rot45( t[0], from );
from = t[0];
case VIPS_ANGLE45_225:
vips_rot45_rot45( t[0], from );
from = t[0];
case VIPS_ANGLE45_180:
vips_rot45_rot45( t[0], from );
from = t[0];
case VIPS_ANGLE45_135:
vips_rot45_rot45( t[0], from );
from = t[0];
case VIPS_ANGLE45_90:
vips_rot45_rot45( t[0], from );
from = t[0];
case VIPS_ANGLE45_45:
vips_rot45_rot45( t[0], from );
from = t[0];
break;
default:
g_assert( 0 );
/* Keep -Wall happy.
*/
return( 0 );
}
if( vips_image_write( t[0], conversion->out ) )
return( -1 );
return( 0 );
}
static void
vips_rot45_class_init( VipsRot45Class *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
VIPS_DEBUG_MSG( "vips_rot45_class_init\n" );
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
vobject_class->nickname = "rot45";
vobject_class->description = _( "rotate an image" );
vobject_class->build = vips_rot45_build;
VIPS_ARG_IMAGE( class, "in", 1,
_( "Input" ),
_( "Input image" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsRot45, in ) );
VIPS_ARG_ENUM( class, "angle", 6,
_( "Angle" ),
_( "Angle to rotate image" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsRot45, angle ),
VIPS_TYPE_ANGLE45, VIPS_ANGLE45_45 );
}
static void
vips_rot45_init( VipsRot45 *rot45 )
{
rot45->angle = VIPS_ANGLE45_45;
}
/**
* vips_rot45:
* @in: input image
* @out: output image
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* @angle: rotation angle
*
* Rotate @in by a multiple of 45 degrees. Odd-length sides and square images
* only.
*
* See also: vips_rot().
*
* Returns: 0 on success, -1 on error
*/
int
vips_rot45( VipsImage *in, VipsImage **out, ... )
{
va_list ap;
int result;
va_start( ap, out );
result = vips_call_split( "rot45", ap, in, out );
va_end( ap );
return( result );
}

View File

@ -273,10 +273,9 @@ vips_sequential_build( VipsObject *object )
vips_object_local( object, t );
if( vips_image_copy_fields( conversion->out, t ) )
if( vips_image_pipelinev( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, t, NULL ) )
return( -1 );
vips_demand_hint( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, t, NULL );
if( vips_image_generate( conversion->out,
vips_start_one, vips_sequential_generate, vips_stop_one,
t, sequential ) )

View File

@ -209,10 +209,14 @@ vips_subsample_build( VipsObject *object )
vips_check_coding_known( class->nickname, subsample->in ) )
return( -1 );
/* Set demand hints. We want THINSTRIP, as we will be demanding a
* large area of input for each output line.
*/
if( vips_image_pipelinev( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, subsample->in, NULL ) )
return( -1 );
/* Prepare output. Note: we round the output width down!
*/
if( vips_image_copy_fields( conversion->out, subsample->in ) )
return( -1 );
conversion->out->Xsize = subsample->in->Xsize / subsample->xfac;
conversion->out->Ysize = subsample->in->Ysize / subsample->yfac;
conversion->out->Xres = subsample->in->Xres / subsample->xfac;
@ -224,12 +228,6 @@ vips_subsample_build( VipsObject *object )
return( -1 );
}
/* Set demand hints. We want THINSTRIP, as we will be demanding a
* large area of input for each output line.
*/
vips_demand_hint( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, subsample->in, NULL );
/* Generate! If this is a very large shrink, then it's
* probably faster to do it a pixel at a time.
*/

View File

@ -740,10 +740,9 @@ vips_tile_cache_build( VipsObject *object )
if( vips_image_pio_input( block_cache->in ) )
return( -1 );
if( vips_image_copy_fields( conversion->out, block_cache->in ) )
if( vips_image_pipelinev( conversion->out,
VIPS_DEMAND_STYLE_SMALLTILE, block_cache->in, NULL ) )
return( -1 );
vips_demand_hint( conversion->out,
VIPS_DEMAND_STYLE_SMALLTILE, block_cache->in, NULL );
if( vips_image_generate( conversion->out,
vips_start_one, vips_tile_cache_gen, vips_stop_one,
@ -926,10 +925,9 @@ vips_line_cache_build( VipsObject *object )
if( vips_image_pio_input( block_cache->in ) )
return( -1 );
if( vips_image_copy_fields( conversion->out, block_cache->in ) )
if( vips_image_pipelinev( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, block_cache->in, NULL ) )
return( -1 );
vips_demand_hint( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, block_cache->in, NULL );
if( vips_image_generate( conversion->out,
vips_start_one, vips_line_cache_gen, vips_stop_one,

View File

@ -349,13 +349,12 @@ vips_zoom_build( VipsObject *object )
vips_check_coding_known( class->nickname, zoom->in ) )
return( -1 );
if( vips_image_copy_fields( conversion->out, zoom->in ) )
return( -1 );
/* Set demand hints. THINSTRIP will prevent us from using
* vips_zoom_paint_whole() much ... so go for FATSTRIP.
*/
vips_demand_hint( conversion->out,
VIPS_DEMAND_STYLE_FATSTRIP, zoom->in, NULL );
if( vips_image_pipelinev( conversion->out,
VIPS_DEMAND_STYLE_FATSTRIP, zoom->in, NULL ) )
return( -1 );
conversion->out->Xsize = zoom->in->Xsize * zoom->xfac;
conversion->out->Ysize = zoom->in->Ysize * zoom->yfac;

View File

@ -4,9 +4,10 @@ libconvolution_la_SOURCES = \
convolution.c \
pconvolution.h \
conv.c \
convsep.c \
compass.c \
morph.c \
convol_dispatch.c \
im_addgnoise.c \
im_compass.c \
im_aconv.c \
im_aconvsep.c \
im_conv.c \

View File

@ -0,0 +1,214 @@
/* repeatedly convolve with a rotating mask
*
* 23/10/13
* - from vips_conv()
*/
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 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 <stdio.h>
#include <vips/vips.h>
#include "pconvolution.h"
typedef struct {
VipsConvolution parent_instance;
int times;
VipsAngle45 angle;
VipsCombine combine;
VipsPrecision precision;
int layers;
int cluster;
} VipsCompass;
typedef VipsConvolutionClass VipsCompassClass;
G_DEFINE_TYPE( VipsCompass, vips_compass, VIPS_TYPE_CONVOLUTION );
static int
vips_compass_build( VipsObject *object )
{
VipsConvolution *convolution = (VipsConvolution *) object;
VipsCompass *compass = (VipsCompass *) object;
VipsImage **masks;
VipsImage *mask;
VipsImage **images;
int i;
VipsImage **abs;
VipsImage **combine;
VipsImage *x;
g_object_set( compass, "out", vips_image_new(), NULL );
if( VIPS_OBJECT_CLASS( vips_compass_parent_class )->build( object ) )
return( -1 );
masks = (VipsImage **)
vips_object_local_array( object, compass->times );
images = (VipsImage **)
vips_object_local_array( object, compass->times );
abs = (VipsImage **)
vips_object_local_array( object, compass->times );
combine = (VipsImage **)
vips_object_local_array( object, compass->times );
mask = convolution->M;
for( i = 0; i < compass->times; i++ ) {
if( vips_conv( convolution->in, &images[i], mask,
"precision", compass->precision,
"layers", compass->layers,
"cluster", compass->cluster,
NULL ) )
return( -1 );
if( vips_rot45( mask, &masks[i],
"angle", compass->angle,
NULL ) )
return( -1 );
mask = masks[i];
}
for( i = 0; i < compass->times; i++ )
if( vips_abs( images[i], &abs[i], NULL ) )
return( -1 );
switch( compass->combine ) {
case VIPS_COMBINE_MAX:
if( vips_bandrank( abs, &combine[0], compass->times,
"index", compass->times - 1,
NULL ) )
return( -1 );
x = combine[0];
break;
case VIPS_COMBINE_SUM:
x = abs[0];
for( i = 1; i < compass->times; i++ ) {
if( vips_add( x, abs[i], &combine[i], NULL ) )
return( -1 );
x = combine[i];
}
break;
default:
g_assert( 0 );
}
if( vips_image_write( x, convolution->out ) )
return( -1 );
return( 0 );
}
static void
vips_compass_class_init( VipsCompassClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "compass";
object_class->description = _( "convolution operation" );
object_class->build = vips_compass_build;
VIPS_ARG_INT( class, "times", 101,
_( "Times" ),
_( "Rotate and convolve this many times" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsCompass, times ),
1, 1000, 2 );
VIPS_ARG_ENUM( class, "angle", 103,
_( "Angle" ),
_( "Rotate mask by this much between convolutions" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsCompass, angle ),
VIPS_TYPE_ANGLE45, VIPS_ANGLE45_90 );
VIPS_ARG_ENUM( class, "combine", 104,
_( "Combine" ),
_( "Combine convolution results like this" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsCompass, combine ),
VIPS_TYPE_COMBINE, VIPS_COMBINE_MAX );
VIPS_ARG_ENUM( class, "precision", 203,
_( "Precision" ),
_( "Convolve with this precision" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsCompass, precision ),
VIPS_TYPE_PRECISION, VIPS_PRECISION_INTEGER );
VIPS_ARG_INT( class, "layers", 204,
_( "Layers" ),
_( "Use this many layers in approximation" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsCompass, layers ),
1, 1000, 5 );
VIPS_ARG_INT( class, "cluster", 205,
_( "Cluster" ),
_( "Cluster lines closer than this in approximation" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsCompass, cluster ),
1, 100, 1 );
}
static void
vips_compass_init( VipsCompass *compass )
{
compass->times = 2;
compass->angle = VIPS_ANGLE45_90;
compass->combine = VIPS_COMBINE_MAX;
compass->precision = VIPS_PRECISION_INTEGER;
compass->layers = 5;
compass->cluster = 1;
}
int
vips_compass( VipsImage *in, VipsImage **out, VipsImage *mask, ... )
{
va_list ap;
int result;
va_start( ap, mask );
result = vips_call_split( "compass", ap, in, out, mask );
va_end( ap );
return( result );
}

View File

@ -62,6 +62,7 @@ G_DEFINE_TYPE( VipsConv, vips_conv, VIPS_TYPE_CONVOLUTION );
static int
vips_conv_build( VipsObject *object )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsConvolution *convolution = (VipsConvolution *) object;
VipsConv *conv = (VipsConv *) object;
@ -73,27 +74,32 @@ vips_conv_build( VipsObject *object )
if( VIPS_OBJECT_CLASS( vips_conv_parent_class )->build( object ) )
return( -1 );
/*
printf( "vips_conv_build: convolving with:\n" );
vips_matrixprint( convolution->M, NULL );
*/
if( !(imsk = im_vips2imask( convolution->M, class->nickname )) ||
!im_local_imask( convolution->out, imsk ) )
return( -1 );
if( !(dmsk = im_vips2mask( convolution->M, class->nickname )) ||
!im_local_dmask( convolution->out, dmsk ) )
return( -1 );
switch( conv->precision ) {
case VIPS_PRECISION_INTEGER:
if( !(imsk = im_vips2imask( convolution->M, "im_stats" )) ||
!im_local_imask( convolution->out, imsk ) ||
im_conv( convolution->in, convolution->out, imsk ) )
if( im_conv( convolution->in, convolution->out, imsk ) )
return( -1 );
break;
case VIPS_PRECISION_FLOAT:
if( !(dmsk = im_vips2mask( convolution->M, "im_stats" )) ||
!im_local_dmask( convolution->out, dmsk ) ||
im_conv_f( convolution->in, convolution->out, dmsk ) )
if( im_conv_f( convolution->in, convolution->out, dmsk ) )
return( -1 );
break;
case VIPS_PRECISION_APPROXIMATE:
if( !(dmsk = im_vips2mask( convolution->M, "im_stats" )) ||
!im_local_dmask( convolution->out, dmsk ) ||
im_aconv( convolution->in, convolution->out, dmsk,
conv->layers, conv->cluster ) )
if( im_aconv( convolution->in, convolution->out, dmsk,
conv->layers, conv->cluster ) )
return( -1 );
break;

View File

@ -78,8 +78,8 @@ G_DEFINE_ABSTRACT_TYPE( VipsConvolution, vips_convolution,
static int
vips_convolution_build( VipsObject *object )
{
VipsConvolution *convolution = VIPS_CONVOLUTION( object );
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsConvolution *convolution = VIPS_CONVOLUTION( object );
VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 );
#ifdef DEBUG
@ -127,7 +127,7 @@ vips_convolution_class_init( VipsConvolutionClass *class )
VIPS_ARGUMENT_REQUIRED_OUTPUT,
G_STRUCT_OFFSET( VipsConvolution, out ) );
VIPS_ARG_IMAGE( class, "mask", 102,
VIPS_ARG_IMAGE( class, "mask", 20,
_( "Mask" ),
_( "Input matrix image" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
@ -147,6 +147,12 @@ void
vips_convolution_operation_init( void )
{
extern int vips_conv_get_type( void );
extern int vips_morph_get_type( void );
extern int vips_compass_get_type( void );
extern int vips_convsep_get_type( void );
vips_conv_get_type();
vips_morph_get_type();
vips_compass_get_type();
vips_convsep_get_type();
}

View File

@ -0,0 +1,173 @@
/* convolve twice, rotating the mask
*
* 23/10/13
* - from vips_convsep()
*/
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 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 <stdio.h>
#include <vips/vips.h>
#include "pconvolution.h"
typedef struct {
VipsConvolution parent_instance;
VipsPrecision precision;
int layers;
int cluster;
} VipsConvsep;
typedef VipsConvolutionClass VipsConvsepClass;
G_DEFINE_TYPE( VipsConvsep, vips_convsep, VIPS_TYPE_CONVOLUTION );
static int
vips_convsep_build( VipsObject *object )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsConvolution *convolution = (VipsConvolution *) object;
VipsConvsep *convsep = (VipsConvsep *) object;
VipsImage **t = (VipsImage **)
vips_object_local_array( object, 3 );
g_object_set( convsep, "out", vips_image_new(), NULL );
if( VIPS_OBJECT_CLASS( vips_convsep_parent_class )->build( object ) )
return( -1 );
if( vips_check_separable( class->nickname, convolution->M ) )
return( -1 );
if( vips_rot( convolution->M, &t[0], VIPS_ANGLE_90, NULL ) ||
vips_conv( convolution->in, &t[1], convolution->M,
"precision", convsep->precision,
"layers", convsep->layers,
"cluster", convsep->cluster,
NULL ) ||
vips_conv( t[1], &t[2], t[0],
"precision", convsep->precision,
"layers", convsep->layers,
"cluster", convsep->cluster,
NULL ) )
return( -1 );
if( vips_image_write( t[2], convolution->out ) )
return( -1 );
return( 0 );
}
static void
vips_convsep_class_init( VipsConvsepClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "convsep";
object_class->description = _( "convolution operation" );
object_class->build = vips_convsep_build;
VIPS_ARG_ENUM( class, "precision", 203,
_( "Precision" ),
_( "Convolve with this precision" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsConvsep, precision ),
VIPS_TYPE_PRECISION, VIPS_PRECISION_INTEGER );
VIPS_ARG_INT( class, "layers", 204,
_( "Layers" ),
_( "Use this many layers in approximation" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsConvsep, layers ),
1, 1000, 5 );
VIPS_ARG_INT( class, "cluster", 205,
_( "Cluster" ),
_( "Cluster lines closer than this in approximation" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsConvsep, cluster ),
1, 100, 1 );
}
static void
vips_convsep_init( VipsConvsep *convsep )
{
convsep->precision = VIPS_PRECISION_INTEGER;
convsep->layers = 5;
convsep->cluster = 1;
}
/**
* vips_convsep:
* @in: input image
* @out: output image
* @mask: convolution mask
*
* Optional arguments:
*
* @precision: calculation accuracy
* @layers: number of layers for approximation
* @cluster: cluster lines closer than this distance
*
* Perform a separable convolution of @in with @mask.
* See vips_conv() for a detailed description.
*
* The mask must be 1xn or nx1 elements.
*
* The image is convolved twice: once with @mask and then again with @mask
* rotated by 90 degrees. This is much faster for certain types of mask
* (gaussian blur, for example) than doing a full 2D convolution.
*
* See also: vips_conv(), vips_gaussmat().
*
* Returns: 0 on success, -1 on error
*/
int
vips_convsep( VipsImage *in, VipsImage **out, VipsImage *mask, ... )
{
va_list ap;
int result;
va_start( ap, mask );
result = vips_call_split( "convsep", ap, in, out, mask );
va_end( ap );
return( result );
}

View File

@ -1,83 +0,0 @@
/* im_addgnoise
*
* Copyright 1990, N. Dessipris.
*
* File written on 2/12/1986
* Author : N. Dessipris
* Updated : 22/01/1991
* 1/2/95 JC
* - junked!
* - now uses partial im_gaussnoise() and partial im_add() to do the
* same job
& 1/5/01 JC
* - oops, failed for not-1-band images
*
* 2008-01-28 tcv:
* - now works (was broken)
* - no limit on bands
* 4/2/10
* - no need to bandup here now, im_add() does that
* - gtkdoc
*/
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 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 <vips/vips.h>
/**
* im_addgnoise:
* @in: input image
* @out: output image
* @sigma: standard deviation of noise
*
* Add gaussian noise with mean 0 and variance sigma to @in.
* The noise is generated by averaging 12 random numbers,
* see page 78, PIETGEN, 1989.
*
* See also: im_gaussnoise().
*
* Returns: 0 on success, -1 on error
*/
int
im_addgnoise( IMAGE *in, IMAGE *out, double sigma )
{
IMAGE *t;
if( !(t = im_open_local( out, "im_addgnoise", "p" )) ||
im_gaussnoise( t, in->Xsize, in->Ysize, 0, sigma ) ||
im_add( in, t, out ) )
return( -1 );
return( 0 );
}

View File

@ -1,158 +0,0 @@
/* im_compass
*
* Author: N. Dessipris (Copyright, N. Dessipris 1991)
* Written on: 08/05/1991
* Modified on:
* 11/3/01 JC
* - rewritten, calling im_conv() and im_maxvalue()
* 3/2/10
* - gtkdoc
*/
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 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 <vips/vips.h>
/**
* im_compass:
* @in: input image
* @out: output image
* @mask: convolution mask
*
* @in is convolved 8 times with @mask, each time @mask is rotated by 45
* degrees. Each output pixel is the largest absolute value of the 8
* convolutions.
*
* See also: im_lindetect(), im_gradient(), im_conv().
*
* Returns: 0 on success, -1 on error
*/
int
im_compass( IMAGE *in, IMAGE *out, INTMASK *mask )
{
IMAGE *filtered[8];
IMAGE *absed[8];
int i;
if( im_open_local_array( out, filtered, 8, "im_compass:1", "p" ) ||
im_open_local_array( out, absed, 8, "im_compass:2", "p" ) )
return( -1 );
for( i = 0; i < 8; i++ ) {
if( im_conv( in, filtered[i], mask ) ||
!(mask = im_local_imask( out,
im_rotate_imask45( mask, mask->filename ) )) )
return( -1 );
}
for( i = 0; i < 8; i++ )
if( im_abs( filtered[i], absed[i] ) )
return( -1 );
return( im_maxvalue( absed, out, 8 ) );
}
/**
* im_lindetect:
* @in: input image
* @out: output image
* @mask: convolution mask
*
* @in is convolved four times with @mask, each time @mask is rotated by 45
* degrees. Each output pixel is the largest absolute value of the four
* convolutions.
*
* See also: im_compass(), im_gradient(), im_conv().
*
* Returns: 0 on success, -1 on error
*/
int
im_lindetect( IMAGE *in, IMAGE *out, INTMASK *mask )
{
IMAGE *filtered[4];
IMAGE *absed[4];
int i;
if( im_open_local_array( out, filtered, 4, "im_lindetect:1", "p" ) ||
im_open_local_array( out, absed, 4, "im_lindetect:2", "p" ) )
return( -1 );
for( i = 0; i < 4; i++ ) {
if( im_conv( in, filtered[i], mask ) ||
!(mask = im_local_imask( out,
im_rotate_imask45( mask, mask->filename ) )) )
return( -1 );
}
for( i = 0; i < 4; i++ )
if( im_abs( filtered[i], absed[i] ) )
return( -1 );
return( im_maxvalue( absed, out, 4 ) );
}
/**
* im_gradient:
* @in: input image
* @out: output image
* @mask: convolution mask
*
* @in is convolved with @mask and with @mask after a 90 degree rotation. The
* result is the sum of the absolute value of the two convolutions.
*
* See also: im_lindetect(), im_gradient(), im_conv().
*
* Returns: 0 on success, -1 on error
*/
int
im_gradient( IMAGE *in, IMAGE *out, INTMASK *mask )
{
IMAGE *t[4];
INTMASK *rmask;
if( im_open_local_array( out, t, 4, "im_gradient", "p" ) )
return( -1 );
if( !(rmask = im_local_imask( out,
im_rotate_imask90( mask, mask->filename ) )) )
return( -1 );
if( im_conv( in, t[0], mask ) ||
im_conv( in, t[1], rmask ) ||
im_abs( t[0], t[2] ) ||
im_abs( t[1], t[3] ) ||
im_add( t[2], t[3], out ) )
return( -1 );
return( 0 );
}

View File

@ -1075,28 +1075,6 @@ im_conv_raw( IMAGE *in, IMAGE *out, INTMASK *mask )
return( 0 );
}
/**
* im_conv:
* @in: input image
* @out: output image
* @mask: convolution mask
*
* Convolve @in with @mask using integer arithmetic. The output image
* always has the same #VipsBandFmt as the input image.
*
* Each output pixel is
* calculated as sigma[i]{pixel[i] * mask[i]} / scale + offset, where scale
* and offset are part of @mask. For integer @in, the division by scale
* includes round-to-nearest.
*
* Convolutions on unsigned 8-bit images are calculated with the
* processor's vector unit,
* if possible. Disable this with --vips-novector or IM_NOVECTOR.
*
* See also: im_conv_f(), im_convsep(), im_create_imaskv().
*
* Returns: 0 on success, -1 on error
*/
int
im_conv( IMAGE *in, IMAGE *out, INTMASK *mask )
{
@ -1114,72 +1092,3 @@ im_conv( IMAGE *in, IMAGE *out, INTMASK *mask )
return( 0 );
}
int
im_convsep_raw( IMAGE *in, IMAGE *out, INTMASK *mask )
{
IMAGE *t;
INTMASK *rmask;
if( mask->xsize != 1 && mask->ysize != 1 ) {
im_error( "im_convsep",
"%s", _( "expect 1xN or Nx1 input mask" ) );
return( -1 );
}
if( !(t = im_open_local( out, "im_convsep", "p" )) ||
!(rmask = (INTMASK *) im_local( out,
(im_construct_fn) im_dup_imask,
(im_callback_fn) im_free_imask, mask, mask->filename, NULL )) )
return( -1 );
rmask->xsize = mask->ysize;
rmask->ysize = mask->xsize;
rmask->offset = 0.;
if( im_conv_raw( in, t, rmask ) ||
im_conv_raw( t, out, mask ) )
return( -1 );
return( 0 );
}
/**
* im_convsep:
* @in: input image
* @out: output image
* @mask: convolution mask
*
* Perform a separable convolution of @in with @mask using integer arithmetic.
* See im_conv() for a detailed description.
*
* The mask must be 1xn or nx1 elements.
* The output image
* always has the same #VipsBandFmt as the input image.
*
* The image is convolved twice: once with @mask and then again with @mask
* rotated by 90 degrees. This is much faster for certain types of mask
* (gaussian blur, for example) than doing a full 2D convolution.
*
* See also: im_convsep_f(), im_conv(), im_create_imaskv().
*
* Returns: 0 on success, -1 on error
*/
int
im_convsep( IMAGE *in, IMAGE *out, INTMASK *mask )
{
IMAGE *t1 = im_open_local( out, "im_convsep intermediate", "p" );
int n_mask = mask->xsize * mask->ysize;
if( !t1 ||
im_embed( in, t1, 1, n_mask / 2, n_mask / 2,
in->Xsize + n_mask - 1,
in->Ysize + n_mask - 1 ) ||
im_convsep_raw( t1, out, mask ) )
return( -1 );
out->Xoffset = 0;
out->Yoffset = 0;
return( 0 );
}

View File

@ -392,77 +392,3 @@ im_conv_f( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
return( 0 );
}
int
im_convsep_f_raw( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
{
IMAGE *t;
DOUBLEMASK *rmask;
if( mask->xsize != 1 && mask->ysize != 1 ) {
im_error( "im_convsep_f",
"%s", _( "expect 1xN or Nx1 input mask" ) );
return( -1 );
}
if( !(t = im_open_local( out, "im_convsep_f", "p" )) ||
!(rmask = (DOUBLEMASK *) im_local( out,
(im_construct_fn) im_dup_dmask,
(im_callback_fn) im_free_dmask, mask, mask->filename, NULL )) )
return( -1 );
rmask->xsize = mask->ysize;
rmask->ysize = mask->xsize;
rmask->offset = 0.;
if( im_conv_f_raw( in, t, rmask ) ||
im_conv_f_raw( t, out, mask ) )
return( -1 );
return( 0 );
}
/**
* im_convsep_f:
* @in: input image
* @out: output image
* @mask: convolution mask
*
* Perform a separable convolution of @in with @mask using floating-point
* arithmetic.
*
* The mask must be 1xn or nx1 elements.
* The output image
* is always %IM_BANDFMT_FLOAT unless @in is %IM_BANDFMT_DOUBLE, in which case
* @out is also %IM_BANDFMT_DOUBLE.
*
* The image is convolved twice: once with @mask and then again with @mask
* rotated by 90 degrees. This is much faster for certain types of mask
* (gaussian blur, for example) than doing a full 2D convolution.
*
* Each output pixel is
* calculated as sigma[i]{pixel[i] * mask[i]} / scale + offset, where scale
* and offset are part of @mask.
*
* See also: im_convsep(), im_conv(), im_create_dmaskv().
*
* Returns: 0 on success, -1 on error
*/
int
im_convsep_f( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
{
IMAGE *t1 = im_open_local( out, "im_convsep intermediate", "p" );
int size = mask->xsize * mask->ysize;
if( !t1 ||
im_embed( in, t1, 1, size / 2, size / 2,
in->Xsize + size - 1,
in->Ysize + size - 1 ) ||
im_convsep_f_raw( t1, out, mask ) )
return( -1 );
out->Xoffset = 0;
out->Yoffset = 0;
return( 0 );
}

179
libvips/convolution/morph.c Normal file
View File

@ -0,0 +1,179 @@
/* morphology
*
* 23/10/13
* - from vips_conv()
*/
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
/* This is a simple wrapper over the old vips7 functions. At some point we
* should rewrite this as a pure vips8 class and redo the vips7 functions as
* wrappers over this.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <vips/vips.h>
#include "pconvolution.h"
typedef struct {
VipsConvolution parent_instance;
VipsOperationMorphology morph;
} VipsMorph;
typedef VipsConvolutionClass VipsMorphClass;
G_DEFINE_TYPE( VipsMorph, vips_morph, VIPS_TYPE_CONVOLUTION );
static int
vips_morph_build( VipsObject *object )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsConvolution *convolution = (VipsConvolution *) object;
VipsMorph *morph = (VipsMorph *) object;
INTMASK *imsk;
g_object_set( morph, "out", vips_image_new(), NULL );
if( VIPS_OBJECT_CLASS( vips_morph_parent_class )->build( object ) )
return( -1 );
if( !(imsk = im_vips2imask( convolution->M, class->nickname )) ||
!im_local_imask( convolution->out, imsk ) )
return( -1 );
switch( morph->morph ) {
case VIPS_OPERATION_MORPHOLOGY_DILATE:
if( im_dilate( convolution->in, convolution->out, imsk ) )
return( -1 );
break;
case VIPS_OPERATION_MORPHOLOGY_ERODE:
if( im_erode( convolution->in, convolution->out, imsk ) )
return( -1 );
break;
default:
g_assert( 0 );
}
return( 0 );
}
static void
vips_morph_class_init( VipsMorphClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "morph";
object_class->description = _( "convolution operation" );
object_class->build = vips_morph_build;
VIPS_ARG_ENUM( class, "morph", 103,
_( "Morphology" ),
_( "Morphological operation to perform" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsMorph, morph ),
VIPS_TYPE_OPERATION_MORPHOLOGY,
VIPS_OPERATION_MORPHOLOGY_ERODE );
}
static void
vips_morph_init( VipsMorph *morph )
{
morph->morph = VIPS_OPERATION_MORPHOLOGY_ERODE;
}
/**
* vips_morph:
* @in: input image
* @out: output image
* @mask: morphology with this mask
* @morph: operation to perform
* @...: %NULL-terminated list of optional named arguments
*
* Performs a morphological operation on @in using @mask as a
* structuring element.
*
* The image should have 0 (black) for no object and 255
* (non-zero) for an object. Note that this is the reverse of the usual
* convention for these operations, but more convenient when combined with the
* boolean operators. The output image is the same
* size as the input image: edge pxels are made by expanding the input image
* as necessary.
*
* Mask coefficients can be either 0 (for object) or 255 (for background)
* or 128 (for do not care). The origin of the mask is at location
* (m.xsize / 2, m.ysize / 2), integer division. All algorithms have been
* based on the book "Fundamentals of Digital Image Processing" by A. Jain,
* pp 384-388, Prentice-Hall, 1989.
*
* For #VIPS_OPERATION_MOPHOLOGY_ERODE,
* the whole mask must match for the output pixel to be
* set, that is, the result is the logical AND of the selected input pixels.
*
* For #VIPS_OPERATION_MOPHOLOGY_DILATE,
* the output pixel is set if any part of the mask
* matches, that is, the result is the logical OR of the selected input pixels.
*
* See the boolean operations vips_andimage(), vips_orimage() and
* vips_eorimage()
* for analogues of the usual set difference and set union operations.
*
* Operations are performed using the processor's vector unit,
* if possible. Disable this with --vips-novector or IM_NOVECTOR.
*
* Returns: 0 on success, -1 on error
*/
int
vips_morph( VipsImage *in, VipsImage **out, VipsImage *mask,
VipsOperationMorphology morph, ... )
{
va_list ap;
int result;
va_start( ap, morph );
result = vips_call_split( "morph", ap, in, out, mask, morph );
va_end( ap );
return( result );
}

View File

@ -3,6 +3,8 @@ noinst_LTLIBRARIES = libcreate.la
libcreate_la_SOURCES = \
create.c \
pcreate.h \
gaussmat.c \
logmat.c \
buildlut.c \
invertlut.c \
tonelut.c \

View File

@ -100,7 +100,7 @@ vips_black_build( VipsObject *object )
black->bands == 1 ?
VIPS_INTERPRETATION_B_W : VIPS_INTERPRETATION_MULTIBAND,
1.0, 1.0 );
vips_demand_hint( create->out,
vips_image_pipelinev( create->out,
VIPS_DEMAND_STYLE_ANY, NULL );
if( vips_image_generate( create->out,

View File

@ -111,6 +111,8 @@ void
vips_create_operation_init( void )
{
extern GType vips_black_get_type( void );
extern GType vips_gaussmat_get_type( void );
extern GType vips_logmat_get_type( void );
extern GType vips_gaussnoise_get_type( void );
#ifdef HAVE_PANGOFT2
extern GType vips_text_get_type( void );
@ -126,6 +128,8 @@ vips_create_operation_init( void )
extern GType vips_identity_get_type( void );
vips_black_get_type();
vips_gaussmat_get_type();
vips_logmat_get_type();
vips_gaussnoise_get_type();
#ifdef HAVE_PANGOFT2
vips_text_get_type();

242
libvips/create/gaussmat.c Normal file
View File

@ -0,0 +1,242 @@
/* generate gaussian images
*
* Written on: 30/11/1989 by Nicos
* Updated on: 6/12/1991
* 7/8/96 JC
* - ansified, mem leaks plugged
* 20/11/98 JC
* - mask too large check added
* 18/3/09
* - bumped max mask size *40
* - added _sep variant
* 30/3/09
* - set scale in _sep variant, why not
* 21/10/10
* - gtkdoc
* 20/10/13
* - redone as a class
*/
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
/*
#define VIPS_DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <vips/vips.h>
#include "pcreate.h"
typedef struct _VipsGaussmat {
VipsCreate parent_instance;
double sigma;
double min_ampl;
gboolean separable;
gboolean integer;
} VipsGaussmat;
typedef struct _VipsGaussmatClass {
VipsCreateClass parent_class;
} VipsGaussmatClass;
G_DEFINE_TYPE( VipsGaussmat, vips_gaussmat, VIPS_TYPE_CREATE );
static int
vips_gaussmat_build( VipsObject *object )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsCreate *create = VIPS_CREATE( object );
VipsGaussmat *gaussmat = (VipsGaussmat *) object;
double sig2 = 2. * gaussmat->sigma * gaussmat->sigma;
int max_x = 8 * gaussmat->sigma > 5000 ? 5000 : 8 * gaussmat->sigma ;
int x, y;
int width, height;
double sum;
if( VIPS_OBJECT_CLASS( vips_gaussmat_parent_class )->build( object ) )
return( -1 );
/* Find the size of the mask. Limit the mask size to 10k x 10k for
* sanity.
*/
for( x = 0; x < max_x; x++ ) {
double v = exp( - ((double)(x * x)) / sig2 );
if( v < gaussmat->min_ampl )
break;
}
if( x == max_x ) {
vips_error( class->nickname, "%s", _( "mask too large" ) );
return( -1 );
}
width = x * 2 + 1;
height = gaussmat->separable ? 1 : width;
vips_image_init_fields( create->out,
width, height, 1,
VIPS_FORMAT_DOUBLE, VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W,
1.0, 1.0 );
vips_image_pipelinev( create->out,
VIPS_DEMAND_STYLE_ANY, NULL );
if( vips_image_write_prepare( create->out ) )
return( -1 );
sum = 0.0;
for( y = 0; y < height; y++ ) {
for( x = 0; x < width; x++ ) {
int xo = x - width / 2;
int yo = y - height / 2;
double distance = xo * xo + yo * yo;
double v = exp( -distance / sig2 );
if( gaussmat->integer )
v = VIPS_RINT( 20 * v );
*VIPS_MATRIX( create->out, x, y ) = v;
sum += v;
}
}
vips_image_set_double( create->out, "scale", sum );
vips_image_set_double( create->out, "offset", 0.0 );
return( 0 );
}
static void
vips_gaussmat_class_init( VipsGaussmatClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
vobject_class->nickname = "gaussmat";
vobject_class->description = _( "make a gaussian image" );
vobject_class->build = vips_gaussmat_build;
VIPS_ARG_DOUBLE( class, "sigma", 2,
_( "Radius" ),
_( "Radius of Gaussian" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsGaussmat, sigma ),
0.000001, 10000.0, 1.0 );
VIPS_ARG_DOUBLE( class, "min_ampl", 3,
_( "Width" ),
_( "Minimum amplitude of Gaussian" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsGaussmat, min_ampl ),
0.000001, 10000.0, 0.1 );
VIPS_ARG_BOOL( class, "separable", 4,
_( "Separable" ),
_( "Generate separable Gaussian" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsGaussmat, separable ),
FALSE );
VIPS_ARG_BOOL( class, "integer", 5,
_( "Integer" ),
_( "Generate integer Gaussian" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsGaussmat, integer ),
FALSE );
}
static void
vips_gaussmat_init( VipsGaussmat *gaussmat )
{
gaussmat->sigma = 1;
gaussmat->min_ampl = 0.1;
}
/**
* vips_gaussmat:
* @sigma: standard deviation of mask
* @min_ampl: minimum amplitude
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* @separable: generate a separable gaussian
* @integer: generate an integer gaussian
*
* Creates a circularly symmetric Gaussian image of radius
* @sigma. The size of the mask is determined by the variable @min_ampl;
* if for instance the value .1 is entered this means that the produced mask
* is clipped at values less than 10 percent of the maximum amplitude.
*
* The program uses the following equation:
*
* H(r) = exp( -(r * r) / (2 * @sigma * @sigma) )
*
* The generated image has odd size and its maximum value is normalised to
* 1.0, unless @integer is set.
*
* If @separable is set, only the centre horizontal is generated. This is
* useful for separable convolutions.
*
* If @integer is set, an integer gaussian is generated. This is useful for
* integer convolutions.
*
* "scale" is set to the sum of all the mask elements.
*
* See also: im_log_dmask(), vips_conv().
*
* Returns: 0 on success, -1 on error
*/
int
vips_gaussmat( VipsImage **out, double sigma, double min_ampl, ... )
{
va_list ap;
int result;
va_start( ap, min_ampl );
result = vips_call_split( "gaussmat", ap, out, sigma, min_ampl );
va_end( ap );
return( result );
}

View File

@ -131,7 +131,7 @@ vips_gaussnoise_build( VipsObject *object )
gaussnoise->width, gaussnoise->height, 1,
VIPS_FORMAT_FLOAT, VIPS_CODING_NONE,
VIPS_INTERPRETATION_B_W, 1.0, 1.0 );
vips_demand_hint( create->out,
vips_image_pipelinev( create->out,
VIPS_DEMAND_STYLE_ANY, NULL );
if( vips_image_generate( create->out,

View File

@ -116,7 +116,7 @@ vips_identity_build( VipsObject *object )
VIPS_CODING_NONE, VIPS_INTERPRETATION_HISTOGRAM,
1.0, 1.0 );
vips_demand_hint( create->out,
vips_image_pipelinev( create->out,
VIPS_DEMAND_STYLE_ANY, NULL );
if( vips_image_generate( create->out,

273
libvips/create/logmat.c Normal file
View File

@ -0,0 +1,273 @@
/* laplacian of logmatian
*
* Written on: 30/11/1989
* Updated on: 6/12/1991
* 7/8/96 JC
* - ansified, mem leaks plugged
* 20/11/98 JC
* - mask too large check added
* 26/3/02 JC
* - ahem, was broken since '96, thanks matt
* 16/7/03 JC
* - makes mask out to zero, not out to minimum, thanks again matt
* 22/10/10
* - gtkdoc
* 20/10/13
* - redone as a class from logmat.c
*/
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
/*
#define VIPS_DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <vips/vips.h>
#include "pcreate.h"
typedef struct _VipsLogmat {
VipsCreate parent_instance;
double sigma;
double min_ampl;
gboolean separable;
gboolean integer;
} VipsLogmat;
typedef struct _VipsLogmatClass {
VipsCreateClass parent_class;
} VipsLogmatClass;
G_DEFINE_TYPE( VipsLogmat, vips_logmat, VIPS_TYPE_CREATE );
static int
vips_logmat_build( VipsObject *object )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsCreate *create = VIPS_CREATE( object );
VipsLogmat *logmat = (VipsLogmat *) object;
double sig2 = logmat->sigma * logmat->sigma;
double last;
int x, y;
int width, height;
double sum;
if( VIPS_OBJECT_CLASS( vips_logmat_parent_class )->build( object ) )
return( -1 );
/* Find the size of the mask. We want to eval the mask out to the
* flat zero part, ie. beyond the minimum and to the point where it
* comes back up towards zero.
*/
last = 0.0;
for( x = 0; x < 5000; x++ ) {
const double distance = x * x;
double val;
/* Handbook of Pattern Recognition and image processing
* by Young and Fu AP 1986 pp 220-221
* temp = (1.0 / (2.0 * IM_PI * sig4)) *
(2.0 - (distance / sig2)) *
exp( (-1.0) * distance / (2.0 * sig2) )
.. use 0.5 to normalise
*/
val = 0.5 *
(2.0 - (distance / sig2)) *
exp( -distance / (2.0 * sig2) );
/* Stop when change in value (ie. difference from the last
* point) is positive (ie. we are going up) and absolute value
* is less than the min.
*/
if( val - last >= 0 &&
fabs( val ) < logmat->min_ampl )
break;
last = val;
}
if( x == 5000 ) {
vips_error( class->nickname, "%s", _( "mask too large" ) );
return( -1 );
}
width = x * 2 + 1;
height = logmat->separable ? 1 : width;
vips_image_init_fields( create->out,
width, height, 1,
VIPS_FORMAT_DOUBLE, VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W,
1.0, 1.0 );
vips_image_pipelinev( create->out,
VIPS_DEMAND_STYLE_ANY, NULL );
if( vips_image_write_prepare( create->out ) )
return( -1 );
sum = 0.0;
for( y = 0; y < height; y++ ) {
for( x = 0; x < width; x++ ) {
int xo = x - width / 2;
int yo = y - height / 2;
double distance = xo * xo + yo * yo;
double v = 0.5 *
(2.0 - (distance / sig2)) *
exp( -distance / (2.0 * sig2) );
if( logmat->integer )
v = VIPS_RINT( 20 * v );
*VIPS_MATRIX( create->out, x, y ) = v;
sum += v;
}
}
vips_image_set_double( create->out, "scale", sum );
vips_image_set_double( create->out, "offset", 0.0 );
return( 0 );
}
static void
vips_logmat_class_init( VipsLogmatClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
vobject_class->nickname = "logmat";
vobject_class->description = _( "make a laplacian of gaussian image" );
vobject_class->build = vips_logmat_build;
VIPS_ARG_DOUBLE( class, "sigma", 2,
_( "Radius" ),
_( "Radius of Logmatian" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsLogmat, sigma ),
0.000001, 10000.0, 1.0 );
VIPS_ARG_DOUBLE( class, "min_ampl", 3,
_( "Width" ),
_( "Minimum amplitude of Logmatian" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsLogmat, min_ampl ),
0.000001, 10000.0, 0.1 );
VIPS_ARG_BOOL( class, "separable", 4,
_( "Separable" ),
_( "Generate separable Logmatian" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsLogmat, separable ),
FALSE );
VIPS_ARG_BOOL( class, "integer", 5,
_( "Integer" ),
_( "Generate integer Logmatian" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsLogmat, integer ),
FALSE );
}
static void
vips_logmat_init( VipsLogmat *logmat )
{
logmat->sigma = 1;
logmat->min_ampl = 0.1;
}
/**
* vips_logmat:
* @sigma: standard deviation of mask
* @min_ampl: minimum amplitude
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* @separable: generate a separable logmatian
* @integer: generate an integer logmatian
*
* Creates a circularly symmetric Laplacian of Gaussian mask
* of radius
* @sigma. The size of the mask is determined by the variable @min_ampl;
* if for instance the value .1 is entered this means that the produced mask
* is clipped at values within 10 persent of zero, and where the change
* between mask elements is less than 10%.
*
* The program uses the following equation: (from Handbook of Pattern
* Recognition and image processing by Young and Fu, AP 1986 pages 220-221):
*
* H(r) = (1 / (2 * M_PI * s4)) *
* (2 - (r2 / s2)) *
* exp(-r2 / (2 * s2))
*
* where s2 = @sigma * @sigma, s4 = s2 * s2, r2 = r * r.
*
* The generated mask has odd size and its maximum value is normalised to
* 1.0, unless @integer is set.
*
* If @separable is set, only the centre horizontal is generated. This is
* useful for separable convolutions.
*
* If @integer is set, an integer logmatian is generated. This is useful for
* integer convolutions.
*
* "scale" is set to the sum of all the mask elements.
*
* See also: vips_gauss(), vips_conv().
*
* Returns: 0 on success, -1 on error
*/
int
vips_logmat( VipsImage **out, double sigma, double min_ampl, ... )
{
va_list ap;
int result;
va_start( ap, min_ampl );
result = vips_call_split( "logmat", ap, out, sigma, min_ampl );
va_end( ap );
return( result );
}

View File

@ -103,7 +103,7 @@ vips_point_build( VipsObject *object )
point->width, point->height, 1,
VIPS_FORMAT_FLOAT, VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W,
1.0, 1.0 );
vips_demand_hint( t[0],
vips_image_pipelinev( t[0],
VIPS_DEMAND_STYLE_ANY, NULL );
if( vips_image_generate( t[0],
NULL, vips_point_gen, NULL, point, NULL ) )

View File

@ -233,7 +233,7 @@ vips_text_build( VipsObject *object )
text->bitmap.width, text->bitmap.rows, 1,
VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W,
1.0, 1.0 );
vips_demand_hint( create->out,
vips_image_pipelinev( create->out,
VIPS_DEMAND_STYLE_ANY, NULL );
for( y = 0; y < text->bitmap.rows; y++ )

View File

@ -163,7 +163,7 @@ vips_xyz_build( VipsObject *object )
VIPS_FORMAT_UINT, VIPS_CODING_NONE,
VIPS_INTERPRETATION_MULTIBAND,
1.0, 1.0 );
vips_demand_hint( create->out,
vips_image_pipelinev( create->out,
VIPS_DEMAND_STYLE_ANY, NULL );
if( vips_image_generate( create->out,

View File

@ -45,8 +45,6 @@ libdeprecated_la_SOURCES = \
im_mask2vips.c \
im_vips2mask.c \
rotmask.c \
im_gaussmasks.c \
im_logmasks.c \
rw_mask.c \
im_matcat.c \
im_matinv.c \

View File

@ -1,280 +0,0 @@
/* generate gaussian masks
*
* Written on: 30/11/1989 by Nicos
* Updated on: 6/12/1991
* 7/8/96 JC
* - ansified, mem leaks plugged
* 20/11/98 JC
* - mask too large check added
* 18/3/09
* - bumped max mask size *40
* - added _sep variant
* 30/3/09
* - set scale in _sep variant, why not
* 21/10/10
* - gtkdoc
*/
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 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 <stdio.h>
#include <math.h>
#include <vips/vips.h>
#define IM_MAXMASK 5000
/**
* im_gauss_dmask:
* @filename: the returned mask has this set as the filename
* @sigma: standard deviation of mask
* @min_ampl: minimum amplitude
*
* im_gauss_dmask() creates a circularly symmetric Gaussian mask of radius
* @sigma. The size of the mask is determined by the variable @min_ampl;
* if for instance the value .1 is entered this means that the produced mask
* is clipped at values less than 10 percent of the maximum amplitude.
*
* The program uses the following equation:
*
* H(r) = exp( -(r * r) / (2 * sigma * sigma) )
*
* The generated mask has odd size and its maximum value is normalised to
* 1.0.
*
* See also: im_gauss_imask(), im_gauss_imask_sep(), im_log_dmask(), im_conv().
*
* Returns: the calculated mask on success, or NULL on error.
*/
DOUBLEMASK *
im_gauss_dmask( const char *filename, double sigma, double min_ampl )
{
int x, y, k;
double distance;
double temp;
double *pt1, *pt2, *pt3, *pt4;
int max_x;
int xm, ym;
int xm2, ym2; /* xm2 = xm/2 */
int offset;
double *cf, *cfs, *mc;
DOUBLEMASK *m;
double sig2, sum; /* sig2 = 2. * sigma * sigma */
/* Find the size of the mask depending on the entered data
*/
sig2 = 2. * sigma * sigma;
max_x = 8 * sigma > IM_MAXMASK ? IM_MAXMASK : 8 * sigma ;
for( x = 0; x < max_x; x++ ) {
temp = exp( - ((double)(x * x))/sig2 );
if( temp < min_ampl )
break;
}
if( x == max_x ) {
im_error( "im_gauss_dmask", "%s", _( "mask too large" ) );
return( NULL );
}
xm2 = x;
ym2 = x;
xm = xm2 * 2 + 1;
ym = ym2 * 2 + 1;
if( !(cfs = IM_ARRAY( NULL, (xm2+1)*(ym2+1), double )) )
return( NULL );
for( k = 0, y = 0; y <= ym2; y++ ) {
for( x = 0; x <= xm2; x++, k++ ) {
distance = x*x + y*y;
cfs[k] = exp( -distance / sig2 );
}
}
#ifdef PIM_RINT
for( k = 0, y = 0; y <= ymask_2; y++ ) {
for( x = 0; x <= xmask_2; x++, k++ )
fprintf(stderr, "%3.2f ", cfs[k] );
fprintf(stderr, "\n");
}
#endif
if( !(m = im_create_dmask( filename, xm, ym )) ) {
im_free( cfs );
return( NULL );
}
/* copy the 1/4 cfs into the m
*/
cf = cfs;
offset = xm2 * (xm + 1);
mc = m->coeff + offset;
for( y = 0; y <= ym2; y++ ) {
for( x = 0; x <= xm2; x++ ) {
pt1 = mc + (y * xm) + x;
pt2 = mc - (y * xm) + x;
pt3 = mc + (y * xm) - x;
pt4 = mc - (y * xm) - x;
*pt1 = cf[x];
*pt2 = cf[x];
*pt3 = cf[x];
*pt4 = cf[x];
}
cf += (xm2 + 1);
}
im_free( cfs );
sum = 0.0;
for( k = 0, y = 0; y < m->ysize; y++ )
for( x = 0; x < m->xsize; x++, k++ )
sum += m->coeff[k];
m->scale = sum;
m->offset = 0.0;
#ifdef PIM_RINT
im_print_dmask( m );
#endif
return( m );
}
/**
* im_gauss_dmask_sep:
* @filename: the returned mask has this set as the filename
* @sigma: standard deviation of mask
* @min_ampl: minimum amplitude
*
* im_gauss_dmask_sep() works exactly as im_gauss_dmask(), but returns only
* the central line of the mask. This is useful with im_convsepf().
*
* See also: im_gauss_dmask(), im_convsepf().
*
* Returns: the calculated mask on success, or NULL on error.
*/
DOUBLEMASK *
im_gauss_dmask_sep( const char *filename, double sigma, double min_ampl )
{
DOUBLEMASK *im;
DOUBLEMASK *im2;
int i;
double sum;
if( !(im = im_gauss_dmask( filename, sigma, min_ampl )) )
return( NULL );
if( !(im2 = im_create_dmask( filename, im->xsize, 1 )) ) {
im_free_dmask( im );
return( NULL );
}
sum = 0;
for( i = 0; i < im->xsize; i++ ) {
im2->coeff[i] = im->coeff[i + im->xsize * (im->ysize / 2)];
sum += im2->coeff[i];
}
im2->scale = sum;
im_free_dmask( im );
return( im2 );
}
/**
* im_gauss_imask:
* @filename: the returned mask has this set as the filename
* @sigma: standard deviation of mask
* @min_ampl: minimum amplitude
*
* im_gauss_imask() works exactly as im_gauss_dmask(), but the returned mask
* is scaled so that it's maximum value it set to 100.
*
* See also: im_gauss_dmask(), im_gauss_imask_sep(), im_conv(), im_convsep().
*
* Returns: the calculated mask on success, or NULL on error.
*/
INTMASK *
im_gauss_imask( const char *filename, double sigma, double min_ampl )
{
DOUBLEMASK *dm;
INTMASK *im;
if( !(dm = im_gauss_dmask( filename, sigma, min_ampl )) )
return( NULL );
if( !(im = im_scale_dmask( dm, dm->filename )) ) {
im_free_dmask( dm );
return( NULL );
}
im_free_dmask( dm );
return( im ) ;
}
/**
* im_gauss_imask_sep:
* @filename: the returned mask has this set as the filename
* @sigma: standard deviation of mask
* @min_ampl: minimum amplitude
*
* im_gauss_imask_sep() works exactly as im_gauss_imask(), but returns only
* the central line of the mask. This is useful with im_convsep().
*
* See also: im_gauss_dmask(), im_convsep().
*
* Returns: the calculated mask on success, or NULL on error.
*/
INTMASK *
im_gauss_imask_sep( const char *filename, double sigma, double min_ampl )
{
INTMASK *im;
INTMASK *im2;
int i;
int sum;
if( !(im = im_gauss_imask( filename, sigma, min_ampl )) )
return( NULL );
if( !(im2 = im_create_imask( filename, im->xsize, 1 )) ) {
im_free_imask( im );
return( NULL );
}
sum = 0;
for( i = 0; i < im->xsize; i++ ) {
im2->coeff[i] = im->coeff[i + im->xsize * (im->ysize / 2)];
sum += im2->coeff[i];
}
im2->scale = sum;
im_free_imask( im );
return( im2 );
}

View File

@ -1,238 +0,0 @@
/* laplacian of gaussian
*
* Written on: 30/11/1989
* Updated on: 6/12/1991
* 7/8/96 JC
* - ansified, mem leaks plugged
* 20/11/98 JC
* - mask too large check added
* 26/3/02 JC
* - ahem, was broken since '96, thanks matt
* 16/7/03 JC
* - makes mask out to zero, not out to minimum, thanks again matt
* 22/10/10
* - gtkdoc
*/
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
/*
#define PIM_RINT 1
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <math.h>
#include <vips/vips.h>
#include <vips/util.h>
#define IM_MAXMASK 256
/**
* im_log_dmask:
* @filename: the returned mask has this set as the filename
* @sigma: standard deviation of mask
* @min_ampl: minimum amplitude
*
* im_log_dmask() creates a circularly symmetric Laplacian of Gaussian mask
* of radius
* @sigma. The size of the mask is determined by the variable @min_ampl;
* if for instance the value .1 is entered this means that the produced mask
* is clipped at values within 10 persent of zero, and where the change
* between mask elements is less than 10%.
*
* The program uses the following equation: (from Handbook of Pattern
* Recognition and image processing by Young and Fu, AP 1986 pages 220-221):
*
* H(r) = (1 / (2 * M_PI * s4)) *
* (2 - (r2 / s2)) *
* exp(-r2 / (2 * s2))
*
* where s2 = sigma * sigma, s4 = s2 * s2, r2 = r * r.
*
* The generated mask has odd size and its maximum value is normalised to 1.0.
*
* See also: im_log_imask(), im_gauss_dmask(), im_conv().
*
* Returns: the calculated mask on success, or NULL on error.
*/
DOUBLEMASK *
im_log_dmask( const char *filename, double sigma, double min_ampl )
{
const double sig2 = sigma * sigma;
double last;
int x, y, k;
double *pt1, *pt2, *pt3, *pt4;
int xm, ym;
int xm2, ym2; /* xm2 = xm/2 */
int offset;
double *cf, *cfs, *mc;
DOUBLEMASK *m;
double sum;
/* Find the size of the mask depending on the entered data. We want to
* eval the mask out to the flat zero part, ie. beyond the minimum and
* to the point where it comes back up towards zero.
*/
last = 0.0;
for( x = 0; x < IM_MAXMASK; x++ ) {
const double distance = x * x;
double val;
/* Handbook of Pattern Recognition and image processing
* by Young and Fu AP 1986 pp 220-221
* temp = (1.0 / (2.0 * IM_PI * sig4)) *
(2.0 - (distance / sig2)) *
exp( (-1.0) * distance / (2.0 * sig2) )
.. use 0.5 to normalise
*/
val = 0.5 *
(2.0 - (distance / sig2)) *
exp( -distance / (2.0 * sig2) );
/* Stop when change in value (ie. difference from the last
* point) is positive (ie. we are going up) and absolute value
* is less than the min.
*/
if( val - last >= 0 &&
fabs( val ) < min_ampl )
break;
last = val;
}
if( x == IM_MAXMASK ) {
im_error( "im_log_dmask", "%s", _( "mask too large" ) );
return( NULL );
}
xm2 = x;
ym2 = x;
xm = xm2 * 2 + 1;
ym = ym2 * 2 + 1;
if( !(cfs = IM_ARRAY( NULL, (xm2 + 1) * (ym2 + 1), double )) )
return( NULL );
/* Make 1/4 of the mask.
*/
for( k = 0, y = 0; y <= ym2; y++ )
for( x = 0; x <= xm2; x++, k++ ) {
const double distance = x * x + y * y;
cfs[k] = 0.5 *
(2.0 - (distance / sig2)) *
exp( -distance / (2.0 * sig2) );
}
#ifdef PIM_RINT
for( k = 0, y = 0; y <= ym2; y++ ) {
for( x = 0; x <= xm2; x++, k++ )
fprintf( stderr, "%3.2f ", cfs[k] );
fprintf( stderr, "\n" );
}
#endif
if( !(m = im_create_dmask( filename, xm, ym )) ) {
im_free( cfs );
return( NULL );
}
/* Copy the 1/4 cfs into the m
*/
cf = cfs;
offset = xm2 * (xm + 1);
mc = m->coeff + offset;
for( y = 0; y <= ym2; y++ ) {
for( x = 0; x <= xm2; x++ ) {
pt1 = mc + (y * xm) + x;
pt2 = mc - (y * xm) + x;
pt3 = mc + (y * xm) - x;
pt4 = mc - (y * xm) - x;
*pt1 = cf[x];
*pt2 = cf[x];
*pt3 = cf[x];
*pt4 = cf[x];
}
cf += (xm2 + 1);
}
im_free( cfs );
sum = 0.0;
for( k = 0, y = 0; y < m->ysize; y++ )
for( x = 0; x < m->xsize; x++, k++ )
sum += m->coeff[k];
m->scale = sum;
m->offset = 0.0;
#ifdef PIM_RINT
im_print_dmask( m );
#endif
return( m );
}
/**
* im_log_imask:
* @filename: the returned mask has this set as the filename
* @sigma: standard deviation of mask
* @min_ampl: minimum amplitude
*
* im_log_imask() works exactly as im_log_dmask(), but the returned mask
* is scaled so that it's maximum value it set to 100.
*
* See also: im_log_dmask(), im_gauss_imask(), im_conv().
*
* Returns: the calculated mask on success, or NULL on error.
*/
INTMASK *
im_log_imask( const char *filename, double sigma, double min_ampl )
{
DOUBLEMASK *dm;
INTMASK *im;
if( !(dm = im_log_dmask( filename, sigma, min_ampl )) )
return( NULL );
if( !(im = im_scale_dmask( dm, dm->filename )) ) {
im_free_dmask( dm );
return( NULL );
}
im_free_dmask( dm );
return( im ) ;
}

View File

@ -101,3 +101,17 @@ im_mask2vips( DOUBLEMASK *in, IMAGE *out )
return( 0 );
}
int
im_imask2vips( INTMASK *in, IMAGE *out )
{
DOUBLEMASK *d;
int result;
if( !(d = im_imask2dmask( in, in->filename )) )
return( -1 );
result = im_mask2vips( d, out );
im_free_dmask( d );
return( result );
}

View File

@ -221,7 +221,7 @@ vips_image_open_lazy( VipsImage *image,
/* Then 'start' creates the real image and 'gen' paints 'image'
* with pixels from the real image on demand.
*/
vips_demand_hint( image, image->dhint, NULL );
vips_image_pipelinev( image, image->dhint, NULL );
if( vips_image_generate( image,
open_lazy_start, open_lazy_generate, vips_stop_one,
lazy, NULL ) )

View File

@ -56,166 +56,6 @@
#include <vips/vips.h>
/* Creates the offsets to rotate by 45 degrees an odd size square mask
*/
int *
im_offsets45( int size )
{
int temp;
int x, y;
int size2 = size * size;
int size_2 = size / 2;
int *pnt, *cpnt1, *cpnt2;
if( size%2 == 0 ) {
im_error( "im_offsets45", "%s", _( "size not odd" ) );
return( NULL );
}
if( !(pnt = IM_ARRAY( NULL, size2, int )) )
return( NULL );
/* point at the beginning and end of the buffer
*/
cpnt1 = pnt; cpnt2 = pnt + size2 - 1;
for( y = 0; y < size_2; y++ ) {
temp = (size_2 + y) * size;
*cpnt1++ = temp;
*cpnt2-- = size2 - 1 - temp;
for( x = 0; x < y; x++ ) {
temp -= (size-1);
*cpnt1++ = temp;
*cpnt2-- = size2 - 1 - temp;
}
for( x = 0; x < size_2 - y; x++ ) {
temp -= size;
*cpnt1++ = temp;
*cpnt2-- = size2 - 1 - temp;
}
for( x = 0; x < size_2 - y; x++ ) {
temp++;
*cpnt1++ = temp;
*cpnt2-- = size2 - 1 - temp;
}
for( x = 0; x < y; x++ ) {
temp -= ( size - 1 );
*cpnt1++ = temp;
*cpnt2-- = size2 - 1 - temp;
}
}
/* the diagonal now
*/
temp = size * (size - 1);
cpnt1 = pnt + size_2 * size;
for( x = 0; x < size; x++ ) {
*cpnt1++ = temp;
temp -= (size-1);
}
#ifdef PIM_RINT
temp = 0;
for( y = 0; y < size; y++ ) {
for( x = 0; x < size; x++ ) {
fprintf( stderr, "%4d", *(pnt+temp) );
temp++;
}
fprintf(stderr, "\n");
}
fprintf(stderr, "\n");
#endif
return( pnt );
}
/**
* im_rotate_dmask45:
* @in: input matrix
* @filename: name for output matrix
*
* Returns a mask which is the argument mask rotated by 45 degrees.
* Pass the filename to set for the output.
*
* See also: im_rotate_dmask90().
*
* Returns: the result matrix on success, or %NULL on error.
*/
DOUBLEMASK *
im_rotate_dmask45( DOUBLEMASK *in, const char *filename )
{
DOUBLEMASK *out;
int size = in->xsize * in->ysize;
int *offsets;
int i;
if( in->xsize != in->ysize || (in->xsize % 2) == 0 ) {
im_error( "im_rotate_dmask45", "%s",
_( "mask should be square of odd size" ) );
return( NULL );
}
if( !(offsets = im_offsets45( in->xsize )) )
return( NULL );
if( !(out = im_create_dmask( filename, in->xsize, in->ysize )) ) {
im_free( offsets );
return( NULL );
}
out->scale = in->scale;
out->offset = in->offset;
for( i = 0; i < size; i++ )
out->coeff[i] = in->coeff[offsets[i]];
im_free( offsets );
return( out );
}
/**
* im_rotate_imask45:
* @in: input matrix
* @filename: name for output matrix
*
* Returns a mask which is the argument mask rotated by 45 degrees.
* Pass the filename to set for the output.
*
* See also: im_rotate_imask90().
*
* Returns: the result matrix on success, or %NULL on error.
*/
INTMASK *
im_rotate_imask45( INTMASK *in, const char *filename )
{
INTMASK *out;
int size = in->xsize * in->ysize;
int *offsets;
int i;
if( in->xsize != in->ysize || (in->xsize % 2) == 0 ) {
im_error( "im_rotate_imask45", "%s",
_( "mask should be square of odd size" ) );
return( NULL );
}
if( !(offsets = im_offsets45( in->xsize )) )
return( NULL );
if( !(out = im_create_imask( filename, in->xsize, in->ysize )) ) {
im_free( offsets );
return( NULL );
}
out->scale = in->scale;
out->offset = in->offset;
for( i = 0; i < size; i++ )
out->coeff[i] = in->coeff[offsets[i]];
im_free( offsets );
return( out );
}
/* The type of the vips operations we support.
*/
typedef int (*vips_fn)( IMAGE *in, IMAGE *out );
@ -273,38 +113,42 @@ vapplydmask( DOUBLEMASK *in, const char *name, vips_fn fn )
return( out );
}
/**
* im_rotate_imask90:
* @in: input matrix
* @filename: name for output matrix
*
* Returns a mask which is the argument mask rotated by 90 degrees.
* Pass the filename to set for the output.
*
* See also: im_rotate_imask45().
*
* Returns: the result matrix on success, or %NULL on error.
*/
INTMASK *
im_rotate_imask90( INTMASK *in, const char *filename )
{
return( vapplyimask( in, filename, im_rot90 ) );
}
/**
* im_rotate_dmask90:
* @in: input matrix
* @filename: name for output matrix
*
* Returns a mask which is the argument mask rotated by 90 degrees.
* Pass the filename to set for the output.
*
* See also: im_rotate_dmask45().
*
* Returns: the result matrix on success, or %NULL on error.
*/
DOUBLEMASK *
im_rotate_dmask90( DOUBLEMASK *in, const char *filename )
{
return( vapplydmask( in, filename, im_rot90 ) );
}
static int
im_rot45( IMAGE *in, IMAGE *out )
{
VipsImage *t;
if( vips_rot45( in, &t, NULL ) )
return( -1 );
if( vips_image_write( t, out ) ) {
g_object_unref( t );
return( -1 );
}
g_object_unref( t );
return( 0 );
}
INTMASK *
im_rotate_imask45( INTMASK *in, const char *filename )
{
return( vapplyimask( in, filename, im_rot45 ) );
}
DOUBLEMASK *
im_rotate_dmask45( DOUBLEMASK *in, const char *filename )
{
return( vapplydmask( in, filename, im_rot45 ) );
}

View File

@ -50,6 +50,12 @@
#include <vips/vector.h>
#include <vips/transform.h>
int
im_init_world( const char *argv0 )
{
return( vips_init( argv0 ) );
}
VipsImage *
im_open( const char *filename, const char *mode )
{
@ -480,7 +486,7 @@ im_wrapmany( IMAGE **in, IMAGE *out, im_wrapmany_fn fn, void *a, void *b )
if( vips_image_pio_input( in[i] ) )
return( -1 );
}
vips_demand_hint_array( out, VIPS_DEMAND_STYLE_THINSTRIP, in );
vips_image_pipeline_array( out, VIPS_DEMAND_STYLE_THINSTRIP, in );
/* Generate!
*/
@ -953,7 +959,35 @@ im_demand_hint (IMAGE * im, VipsDemandStyle hint, ...)
return (-1);
}
return (im_demand_hint_array (im, hint, ar));
vips__demand_hint_array (im, hint, ar);
return (0);
}
int
im_cp_descv (IMAGE * im, ...)
{
va_list ap;
int i;
IMAGE *ar[MAX_IMAGES];
va_start (ap, im);
for (i = 0; i < MAX_IMAGES && (ar[i] = va_arg (ap, IMAGE *)); i++)
;
va_end (ap);
if (i == MAX_IMAGES)
{
im_error ("im_cp_descv", "%s", _("too many images"));
return (-1);
}
return (vips__image_copy_fields_array (im, ar));
}
int
im_cp_desc(IMAGE *out, IMAGE *in )
{
return( im_cp_descv( out, in, NULL));
}
int
@ -1356,6 +1390,30 @@ im_gbandjoin( VipsImage **in, VipsImage *out, int n )
return( 0 );
}
int
im_rank_image( VipsImage **in, VipsImage *out, int n, int index )
{
VipsImage *t;
if( vips_bandrank( in, &t, n,
"index", index,
NULL ) )
return( -1 );
if( vips_image_write( t, out ) ) {
g_object_unref( t );
return( -1 );
}
g_object_unref( t );
return( 0 );
}
int
im_maxvalue( IMAGE **in, IMAGE *out, int n )
{
return( im_rank_image( in, out, n, n - 1 ) );
}
int
im_invert( IMAGE *in, IMAGE *out )
{
@ -1894,6 +1952,119 @@ im_stats( VipsImage *in )
return( msk );
}
DOUBLEMASK *
im_gauss_dmask( const char *filename, double sigma, double min_ampl )
{
VipsImage *t;
DOUBLEMASK *msk;
if( vips_gaussmat( &t, sigma, min_ampl,
NULL ) )
return( NULL );
if( !(msk = im_vips2mask( t, filename )) ) {
g_object_unref( t );
return( NULL );
}
g_object_unref( t );
return( msk );
}
DOUBLEMASK *
im_gauss_dmask_sep( const char *filename, double sigma, double min_ampl )
{
VipsImage *t;
DOUBLEMASK *msk;
if( vips_gaussmat( &t, sigma, min_ampl,
"separable", TRUE,
NULL ) )
return( NULL );
if( !(msk = im_vips2mask( t, filename )) ) {
g_object_unref( t );
return( NULL );
}
g_object_unref( t );
return( msk );
}
INTMASK *
im_gauss_imask( const char *filename, double sigma, double min_ampl )
{
VipsImage *t;
INTMASK *msk;
if( vips_gaussmat( &t, sigma, min_ampl,
"integer", TRUE,
NULL ) )
return( NULL );
if( !(msk = im_vips2imask( t, filename )) ) {
g_object_unref( t );
return( NULL );
}
g_object_unref( t );
return( msk );
}
INTMASK *
im_gauss_imask_sep( const char *filename, double sigma, double min_ampl )
{
VipsImage *t;
INTMASK *msk;
if( vips_gaussmat( &t, sigma, min_ampl,
"integer", TRUE,
"separable", TRUE,
NULL ) )
return( NULL );
if( !(msk = im_vips2imask( t, filename )) ) {
g_object_unref( t );
return( NULL );
}
g_object_unref( t );
return( msk );
}
INTMASK *
im_log_imask( const char *filename, double sigma, double min_ampl )
{
VipsImage *t;
INTMASK *msk;
if( vips_logmat( &t, sigma, min_ampl,
"integer", TRUE,
NULL ) )
return( NULL );
if( !(msk = im_vips2imask( t, filename )) ) {
g_object_unref( t );
return( NULL );
}
g_object_unref( t );
return( msk );
}
DOUBLEMASK *
im_log_dmask( const char *filename, double sigma, double min_ampl )
{
VipsImage *t;
DOUBLEMASK *msk;
if( vips_logmat( &t, sigma, min_ampl,
NULL ) )
return( NULL );
if( !(msk = im_vips2mask( t, filename )) ) {
g_object_unref( t );
return( NULL );
}
g_object_unref( t );
return( msk );
}
int
im_recomb( IMAGE *in, IMAGE *out, DOUBLEMASK *recomb )
{
@ -1917,6 +2088,154 @@ im_recomb( IMAGE *in, IMAGE *out, DOUBLEMASK *recomb )
return( 0 );
}
int
im_compass( VipsImage *in, VipsImage *out, INTMASK *mask )
{
VipsImage *t1, *t2;
if( !(t1 = vips_image_new()) ||
im_imask2vips( mask, t1 ) )
return( -1 );
if( vips_compass( in, &t2, t1,
"times", 8,
NULL ) ) {
g_object_unref( t1 );
return( -1 );
}
g_object_unref( t1 );
if( vips_image_write( t2, out ) ) {
g_object_unref( t2 );
return( -1 );
}
g_object_unref( t2 );
return( 0 );
}
int
im_lindetect( IMAGE *in, IMAGE *out, INTMASK *mask )
{
VipsImage *t1, *t2;
if( !(t1 = vips_image_new()) ||
im_imask2vips( mask, t1 ) )
return( -1 );
if( vips_compass( in, &t2, t1,
"times", 4,
NULL ) ) {
g_object_unref( t1 );
return( -1 );
}
g_object_unref( t1 );
if( vips_image_write( t2, out ) ) {
g_object_unref( t2 );
return( -1 );
}
g_object_unref( t2 );
return( 0 );
}
int
im_gradient( IMAGE *in, IMAGE *out, INTMASK *mask )
{
VipsImage *t1, *t2;
if( !(t1 = vips_image_new()) ||
im_imask2vips( mask, t1 ) )
return( -1 );
if( vips_compass( in, &t2, t1,
"times", 2,
"angle", VIPS_ANGLE45_90,
"combine", VIPS_COMBINE_SUM,
NULL ) ) {
g_object_unref( t1 );
return( -1 );
}
g_object_unref( t1 );
if( vips_image_write( t2, out ) ) {
g_object_unref( t2 );
return( -1 );
}
g_object_unref( t2 );
return( 0 );
}
int
im_convsep_raw( IMAGE *in, IMAGE *out, INTMASK *mask )
{
im_error( "im_convsep_raw", "no compat function" );
return( -1 );
}
int
im_convsep( IMAGE *in, IMAGE *out, INTMASK *mask )
{
VipsImage *t1, *t2;
if( !(t1 = vips_image_new()) ||
im_imask2vips( mask, t1 ) )
return( -1 );
if( vips_convsep( in, &t2, t1,
NULL ) ) {
g_object_unref( t1 );
return( -1 );
}
g_object_unref( t1 );
if( vips_image_write( t2, out ) ) {
g_object_unref( t2 );
return( -1 );
}
g_object_unref( t2 );
return( 0 );
}
int
im_convsep_f_raw( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
{
im_error( "im_convsep_raw", "no compat function" );
return( -1 );
}
int
im_convsep_f( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
{
VipsImage *t1, *t2;
if( !(t1 = vips_image_new()) ||
im_mask2vips( mask, t1 ) )
return( -1 );
if( vips_convsep( in, &t2, t1,
"precision", VIPS_PRECISION_FLOAT,
NULL ) ) {
g_object_unref( t1 );
return( -1 );
}
g_object_unref( t1 );
if( vips_image_write( t2, out ) ) {
g_object_unref( t2 );
return( -1 );
}
g_object_unref( t2 );
return( 0 );
}
int
im_addgnoise( IMAGE *in, IMAGE *out, double sigma )
{
IMAGE *t;
if( !(t = im_open_local( out, "im_addgnoise", "p" )) ||
im_gaussnoise( t, in->Xsize, in->Ysize, 0, sigma ) ||
im_add( in, t, out ) )
return( -1 );
return( 0 );
}
static int
vips__round( VipsImage *in, VipsImage *out, VipsOperationRound round )
{

View File

@ -280,11 +280,11 @@ read_csv( FILE *fp, VipsImage *out,
fsetpos( fp, &pos );
}
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
vips_image_init_fields( out,
columns, lines, 1,
VIPS_FORMAT_DOUBLE,
VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W, 1.0, 1.0 );
vips_demand_hint( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
/* Just reading the header? We are done.
*/
@ -663,12 +663,11 @@ vips__matrix_body( char *whitemap, VipsImage *out, FILE *fp )
}
VipsImage *
vips__matrix_read( const char *filename )
vips__matrix_read_file( FILE *fp )
{
char whitemap[256];
int i;
char *p;
FILE *fp;
int width;
int height;
double scale;
@ -680,13 +679,9 @@ vips__matrix_read( const char *filename )
for( p = WHITESPACE; *p; p++ )
whitemap[(int) *p] = 1;
if( !(fp = vips__file_open_read( filename, NULL, TRUE )) )
return( NULL );
if( vips__matrix_header( whitemap, fp,
&width, &height, &scale, &offset ) ) {
fclose( fp );
&width, &height, &scale, &offset ) )
return( NULL );
}
if( !(out = vips_image_new_matrix( width, height )) )
return( NULL );
@ -695,28 +690,35 @@ vips__matrix_read( const char *filename )
if( vips__matrix_body( whitemap, out, fp ) ) {
g_object_unref( out );
fclose( fp );
return( NULL );
}
fclose( fp );
return( out );
}
VipsImage *
vips__matrix_read( const char *filename )
{
FILE *fp;
VipsImage *out;
if( !(fp = vips__file_open_read( filename, NULL, TRUE )) )
return( NULL );
out = vips__matrix_read_file( fp );
fclose( fp );
return( out );
}
int
vips__matrix_write( VipsImage *in, const char *filename )
vips__matrix_write_file( VipsImage *in, FILE *fp )
{
VipsImage *mask;
FILE *fp;
int x, y;
if( vips_check_matrix( "vips2mask", in, &mask ) )
return( -1 );
if( !(fp = vips__file_open_write( filename, TRUE )) ) {
g_object_unref( mask );
return( -1 );
}
fprintf( fp, "%d %d ", mask->Xsize, mask->Ysize );
if( vips_image_get_typeof( mask, "scale" ) &&
vips_image_get_typeof( mask, "offset" ) )
@ -733,10 +735,23 @@ vips__matrix_write( VipsImage *in, const char *filename )
}
g_object_unref( mask );
fclose( fp );
return( 0 );
}
int
vips__matrix_write( VipsImage *in, const char *filename )
{
FILE *fp;
int result;
if( !(fp = vips__file_open_write( filename, TRUE )) )
return( -1 );
result = vips__matrix_write_file( in, fp );
fclose( fp );
return( result );
}
const char *vips__foreign_matrix_suffs[] = { ".mat", NULL };

View File

@ -48,8 +48,10 @@ int vips__csv_write( VipsImage *in, const char *filename,
int vips__matrix_read_header( const char *filename,
int *width, int *height, double *scale, double *offset );
int vips__matrix_ismatrix( const char *filename );
VipsImage *vips__matrix_read_file( FILE *fp );
VipsImage *vips__matrix_read( const char *filename );
int vips__matrix_write( VipsImage *in, const char *filename );
int vips__matrix_write_file( VipsImage *in, FILE *fp );
extern const char *vips__foreign_matrix_suffs[];

View File

@ -263,7 +263,8 @@ pyramid_build( VipsForeignSaveDz *dz, Layer *above,
* easy.
*/
layer->image = vips_image_new();
if( vips_image_copy_fields( layer->image, save->ready ) ) {
if( vips_image_pipelinev( layer->image,
VIPS_DEMAND_STYLE_ANY, save->ready, NULL ) ) {
layer_free( layer );
return( NULL );
}

View File

@ -296,11 +296,11 @@ vips_fits_get_header( VipsFits *fits, VipsImage *out )
else
type = VIPS_INTERPRETATION_MULTIBAND;
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL );
vips_image_init_fields( out,
width, height, bands,
format,
VIPS_CODING_NONE, type, 1.0, 1.0 );
vips_demand_hint( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL );
/* Read all keys into meta.
*/

View File

@ -776,7 +776,7 @@ vips_foreign_load_start( VipsImage *out, void *a, void *b )
/* We have to tell vips that out depends on real. We've set
* the demand hint below, but not given an input there.
*/
vips_demand_hint( load->out, load->out->dhint,
vips_image_pipelinev( load->out, load->out->dhint,
load->real, NULL );
}
@ -874,7 +874,7 @@ vips_foreign_load_build( VipsObject *object )
/* ->header() should set the dhint. It'll default to the safe
* SMALLTILE if header() did not set it.
*/
vips_demand_hint( load->out, load->out->dhint, NULL );
vips_image_pipelinev( load->out, load->out->dhint, NULL );
/* Then 'start' creates the real image and 'gen' fetches
* pixels for @out from @real on demand.
@ -1611,6 +1611,7 @@ vips_foreign_operation_init( void )
extern GType vips_foreign_save_csv_get_type( void );
extern GType vips_foreign_load_matrix_get_type( void );
extern GType vips_foreign_save_matrix_get_type( void );
extern GType vips_foreign_print_matrix_get_type( void );
extern GType vips_foreign_load_fits_get_type( void );
extern GType vips_foreign_save_fits_get_type( void );
extern GType vips_foreign_load_analyze_get_type( void );
@ -1643,6 +1644,7 @@ vips_foreign_operation_init( void )
vips_foreign_save_csv_get_type();
vips_foreign_load_matrix_get_type();
vips_foreign_save_matrix_get_type();
vips_foreign_print_matrix_get_type();
vips_foreign_load_analyze_get_type();
vips_foreign_load_raw_get_type();
vips_foreign_save_raw_get_type();
@ -1988,6 +1990,7 @@ vips_jpegload( const char *filename, VipsImage **out, ... )
* @Q: quality factor
* @profile: attach this ICC profile
* @optimize_coding: compute optimal Huffman coding tables
* @interlace: write an interlaced (progressive) jpeg
*
* Write a VIPS image to a file as JPEG.
*
@ -2012,6 +2015,13 @@ vips_jpegload( const char *filename, VipsImage **out, ... )
* IPCT as @VIPS_META_IPCT_NAME ("ipct-data") and XMP as VIPS_META_XMP_NAME
* ("xmp-data") are coded and attached.
*
* If @optimize_coding is set, the Huffman tables are optimised. This is
* sllightly slower and produces slightly smaller files.
*
* If @interlace is set, the jpeg files will be interlaced (progressive jpeg,
* in jpg parlance). These files may be better for display over a slow network
* conection, but need much more memory to encode and decode.
*
* See also: vips_jpegsave_buffer(), vips_image_write_file().
*
* Returns: 0 on success, -1 on error.
@ -2041,6 +2051,7 @@ vips_jpegsave( VipsImage *in, const char *filename, ... )
* @Q: JPEG quality factor
* @profile: attach this ICC profile
* @optimize_coding: compute optimal Huffman coding tables
* @interlace: write an interlaced (progressive) jpeg
*
* As vips_jpegsave(), but save to a memory buffer.
*

View File

@ -764,7 +764,7 @@ read_jpeg_header( ReadJpeg *jpeg, VipsImage *out )
interpretation,
xres, yres );
vips_demand_hint( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
/* Interlaced jpegs need lots of memory to read, so our caller needs
* to know.

View File

@ -83,6 +83,10 @@ typedef struct _VipsForeignSaveJpeg {
*/
gboolean optimize_coding;
/* Generate an interlaced (progressive, in jpg terminology) file.
*/
gboolean interlace;
} VipsForeignSaveJpeg;
typedef VipsForeignSaveClass VipsForeignSaveJpegClass;
@ -135,6 +139,13 @@ vips_foreign_save_jpeg_class_init( VipsForeignSaveJpegClass *class )
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveJpeg, optimize_coding ),
FALSE );
VIPS_ARG_BOOL( class, "interlace", 13,
_( "interlace" ),
_( "Generate an interlaced (progressive) jpeg" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveJpeg, interlace ),
FALSE );
}
static void
@ -169,7 +180,8 @@ vips_foreign_save_jpeg_file_build( VipsObject *object )
return( -1 );
if( vips__jpeg_write_file( save->ready, file->filename,
jpeg->Q, jpeg->profile, jpeg->optimize_coding ) )
jpeg->Q, jpeg->profile, jpeg->optimize_coding,
jpeg->interlace ) )
return( -1 );
return( 0 );
@ -234,7 +246,8 @@ vips_foreign_save_jpeg_buffer_build( VipsObject *object )
return( -1 );
if( vips__jpeg_write_buffer( save->ready,
&obuf, &olen, jpeg->Q, jpeg->profile, jpeg->optimize_coding ) )
&obuf, &olen, jpeg->Q, jpeg->profile, jpeg->optimize_coding,
jpeg->interlace ) )
return( -1 );
area = vips_area_new_blob( (VipsCallbackFn) vips_free, obuf, olen );
@ -295,7 +308,8 @@ vips_foreign_save_jpeg_mime_build( VipsObject *object )
return( -1 );
if( vips__jpeg_write_buffer( save->ready,
&obuf, &olen, jpeg->Q, jpeg->profile, jpeg->optimize_coding ) )
&obuf, &olen, jpeg->Q, jpeg->profile, jpeg->optimize_coding,
jpeg->interlace ) )
return( -1 );
printf( "Content-length: %zd\r\n", olen );

View File

@ -337,7 +337,7 @@ parse_header( Read *read )
*/
im->Coding = VIPS_CODING_NONE;
vips_demand_hint( im, VIPS_DEMAND_STYLE_SMALLTILE, NULL );
vips_image_pipelinev( im, VIPS_DEMAND_STYLE_SMALLTILE, NULL );
/* Three ways to loop over attributes / properties :-(
*/

View File

@ -155,3 +155,75 @@ vips_matrixsave( VipsImage *in, const char *filename, ... )
return( result );
}
typedef struct _VipsForeignPrintMatrix {
VipsForeignSave parent_object;
} VipsForeignPrintMatrix;
typedef VipsForeignSaveClass VipsForeignPrintMatrixClass;
G_DEFINE_TYPE( VipsForeignPrintMatrix, vips_foreign_print_matrix,
VIPS_TYPE_FOREIGN_SAVE );
static int
vips_foreign_print_matrix_build( VipsObject *object )
{
VipsForeignSave *save = (VipsForeignSave *) object;
if( VIPS_OBJECT_CLASS( vips_foreign_print_matrix_parent_class )->
build( object ) )
return( -1 );
if( vips__matrix_write_file( save->ready, stdout ) )
return( -1 );
return( 0 );
}
static void
vips_foreign_print_matrix_class_init( VipsForeignPrintMatrixClass *class )
{
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class;
object_class->nickname = "matrixprint";
object_class->description = _( "print matrix" );
object_class->build = vips_foreign_print_matrix_build;
foreign_class->suffs = vips__foreign_matrix_suffs;
save_class->saveable = VIPS_SAVEABLE_MONO;
save_class->format_table = bandfmt_matrix;
}
static void
vips_foreign_print_matrix_init( VipsForeignPrintMatrix *matrix )
{
}
/**
* vips_matrixprint:
* @in: image to print
* @...: %NULL-terminated list of optional named arguments
*
* Print @in to %stdout in matrix format. See vips_matrixload() for a
* description of the format.
*
* See also: vips_matrixload().
*
* Returns: 0 on success, -1 on error.
*/
int
vips_matrixprint( VipsImage *in, ... )
{
va_list ap;
int result;
va_start( ap, in );
result = vips_call_split( "matrixprint", ap, in );
va_end( ap );
return( result );
}

View File

@ -212,9 +212,9 @@ read_header( Read *read, VipsImage *out )
VIPS_FORMAT_FLOAT,
VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB, 1.0, 1.0 );
if( read->tiles )
vips_demand_hint( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL );
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL );
else
vips_demand_hint( out, VIPS_DEMAND_STYLE_FATSTRIP, NULL );
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_FATSTRIP, NULL );
}
int

View File

@ -220,7 +220,7 @@ readslide_new( const char *filename, VipsImage *out,
associated, &w, &h );
vips_image_set_string( out, "slide-associated-image",
associated );
vips_demand_hint( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
}
else {
char buf[256];
@ -231,7 +231,7 @@ readslide_new( const char *filename, VipsImage *out,
rslide->downsample = openslide_get_level_downsample(
rslide->osr, level );
vips_image_set_int( out, "slide-level", level );
vips_demand_hint( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL );
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL );
/* Try to get tile width/height. An undocumented, experimental
* feature.

View File

@ -1236,7 +1236,7 @@ read_tilewise( ReadTiff *rtiff, VipsImage *out )
* the cache we are quite happy serving that if anything downstream
* would like it.
*/
vips_demand_hint( raw, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
vips_image_pipelinev( raw, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
if( vips_image_generate( raw,
tiff_seq_start, tiff_fill_region, tiff_seq_stop,
@ -1413,7 +1413,7 @@ read_stripwise( ReadTiff *rtiff, VipsImage *out )
if( parse_header( rtiff, t[0] ) )
return( -1 );
vips_demand_hint( t[0], VIPS_DEMAND_STYLE_THINSTRIP, NULL );
vips_image_pipelinev( t[0], VIPS_DEMAND_STYLE_THINSTRIP, NULL );
if( !tfget32( rtiff->tiff,
TIFFTAG_ROWSPERSTRIP, &rtiff->rows_per_strip ) )

View File

@ -841,7 +841,7 @@ write_jpeg_block( REGION *region, Rect *area, void *a )
*/
static int
write_vips( Write *write, int qfac, const char *profile,
gboolean optimize_coding )
gboolean optimize_coding, gboolean progressive )
{
VipsImage *in;
J_COLOR_SPACE space;
@ -898,6 +898,11 @@ write_vips( Write *write, int qfac, const char *profile,
*/
write->cinfo.optimize_coding = optimize_coding;
/* Enable progressive write.
*/
if( progressive )
jpeg_simple_progression( &write->cinfo );
/* Build compress tables.
*/
jpeg_start_compress( &write->cinfo, TRUE );
@ -941,7 +946,7 @@ write_vips( Write *write, int qfac, const char *profile,
int
vips__jpeg_write_file( VipsImage *in,
const char *filename, int Q, const char *profile,
gboolean optimize_coding )
gboolean optimize_coding, gboolean progressive )
{
Write *write;
@ -971,7 +976,7 @@ vips__jpeg_write_file( VipsImage *in,
/* Convert!
*/
if( write_vips( write, Q, profile, optimize_coding ) ) {
if( write_vips( write, Q, profile, optimize_coding, progressive ) ) {
write_destroy( write );
return( -1 );
}
@ -1218,7 +1223,7 @@ buf_dest( j_compress_ptr cinfo, void **obuf, size_t *olen )
int
vips__jpeg_write_buffer( VipsImage *in,
void **obuf, size_t *olen, int Q, const char *profile,
gboolean optimize_coding )
gboolean optimize_coding, gboolean progressive )
{
Write *write;
@ -1247,7 +1252,7 @@ vips__jpeg_write_buffer( VipsImage *in,
/* Convert!
*/
if( write_vips( write, Q, profile, optimize_coding ) ) {
if( write_vips( write, Q, profile, optimize_coding, progressive ) ) {
write_destroy( write );
return( -1 );

View File

@ -39,10 +39,10 @@ extern const char *vips__jpeg_suffs[];
int vips__jpeg_write_file( VipsImage *in,
const char *filename, int Q, const char *profile,
gboolean optimize_coding );
gboolean optimize_coding, gboolean progressive );
int vips__jpeg_write_buffer( VipsImage *in,
void **obuf, size_t *olen, int Q, const char *profile,
gboolean optimize_coding );
gboolean optimize_coding, gboolean progressive );
int vips__isjpeg( const char *filename );
int vips__jpeg_read_file( const char *name, VipsImage *out,

View File

@ -351,7 +351,7 @@ png2vips_header( Read *read, VipsImage *out )
/* Sequential mode needs thinstrip to work with things like
* vips_shrink().
*/
vips_demand_hint( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
/* Fetch the ICC profile. @name is useless, something like "icc" or
* "ICC Profile" etc. Ignore it.

View File

@ -153,7 +153,7 @@ read_header( Read *read, VipsImage *out )
VIPS_INTERPRETATION_sRGB,
1.0, 1.0 );
vips_demand_hint( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
return( 0 );
}

View File

@ -256,16 +256,14 @@ vips_hist_local_build( VipsObject *object )
g_object_set( object, "out", vips_image_new(), NULL );
if( vips_image_copy_fields( local->out, in ) )
return( -1 );
local->out->Xsize -= local->width - 1;
local->out->Ysize -= local->height - 1;
/* Set demand hints. FATSTRIP is good for us, as THINSTRIP will cause
* too many recalculations on overlaps.
*/
vips_demand_hint( local->out,
VIPS_DEMAND_STYLE_FATSTRIP, in, NULL );
if( vips_image_pipelinev( local->out,
VIPS_DEMAND_STYLE_FATSTRIP, in, NULL ) )
return( -1 );
local->out->Xsize -= local->width - 1;
local->out->Ysize -= local->height - 1;
if( vips_image_generate( local->out,
vips_hist_local_start,

View File

@ -157,10 +157,9 @@ vips_histogram_build( VipsObject *object )
*/
histogram->ready = size;
if( vips_image_copy_fields_array( histogram->out, histogram->ready ) )
if( vips_image_pipeline_array( histogram->out,
VIPS_DEMAND_STYLE_THINSTRIP, histogram->ready ) )
return( -1 );
vips_demand_hint_array( histogram->out,
VIPS_DEMAND_STYLE_THINSTRIP, histogram->ready );
histogram->out->Xsize = VIPS_IMAGE_N_PELS( histogram->ready[0] );
histogram->out->Ysize = 1;

View File

@ -564,10 +564,9 @@ vips_maplut_build( VipsObject *object )
vips_image_pio_input( in ) )
return( -1 );
if( vips_image_copy_fieldsv( maplut->out, in, lut, NULL ) )
if( vips_image_pipelinev( maplut->out,
VIPS_DEMAND_STYLE_THINSTRIP, in, lut, NULL ) )
return( -1 );
vips_demand_hint( maplut->out, VIPS_DEMAND_STYLE_THINSTRIP,
in, lut, NULL );
maplut->out->BandFmt = lut->BandFmt;
/* Output has same number of bands as LUT, unless LUT has 1 band, in

View File

@ -249,16 +249,14 @@ vips_stdif_build( VipsObject *object )
g_object_set( object, "out", vips_image_new(), NULL );
if( vips_image_copy_fields( stdif->out, in ) )
return( -1 );
stdif->out->Xsize -= stdif->width - 1;
stdif->out->Ysize -= stdif->height - 1;
/* Set demand hints. FATSTRIP is good for us, as THINSTRIP will cause
* too many recalculations on overlaps.
*/
vips_demand_hint( stdif->out,
VIPS_DEMAND_STYLE_FATSTRIP, in, NULL );
if( vips_image_pipelinev( stdif->out,
VIPS_DEMAND_STYLE_FATSTRIP, in, NULL ) )
return( -1 );
stdif->out->Xsize -= stdif->width - 1;
stdif->out->Ysize -= stdif->height - 1;
if( vips_image_generate( stdif->out,
vips_start_one,

View File

@ -65,6 +65,7 @@ vips_scan_headers = \
${top_srcdir}/libvips/include/vips/colour.h \
${top_srcdir}/libvips/include/vips/operation.h \
${top_srcdir}/libvips/include/vips/convolution.h \
${top_srcdir}/libvips/include/vips/morphology.h \
${top_srcdir}/libvips/include/vips/object.h
enumtypes.h: $(vips_scan_headers) Makefile

View File

@ -69,6 +69,18 @@ typedef enum {
VIPS_ANGLE_LAST
} VipsAngle;
typedef enum {
VIPS_ANGLE45_0,
VIPS_ANGLE45_45,
VIPS_ANGLE45_90,
VIPS_ANGLE45_135,
VIPS_ANGLE45_180,
VIPS_ANGLE45_225,
VIPS_ANGLE45_270,
VIPS_ANGLE45_315,
VIPS_ANGLE45_LAST
} VipsAngle45;
int vips_copy( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel));
int vips_tilecache( VipsImage *in, VipsImage **out, ... )
@ -107,6 +119,8 @@ int vips_wrap( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel));
int vips_rot( VipsImage *in, VipsImage **out, VipsAngle angle, ... )
__attribute__((sentinel));
int vips_rot45( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel));
int vips_zoom( VipsImage *in, VipsImage **out, int xfac, int yfac, ... )
__attribute__((sentinel));
int vips_subsample( VipsImage *in, VipsImage **out, int xfac, int yfac, ... )
@ -143,7 +157,7 @@ int vips_bandjoin( VipsImage **in, VipsImage **out, int n, ... )
__attribute__((sentinel));
int vips_bandjoin2( VipsImage *in1, VipsImage *in2, VipsImage **out, ... )
__attribute__((sentinel));
int vips_bandmean( VipsImage *in, VipsImage **out, ... )
int vips_bandrank( VipsImage **in, VipsImage **out, int n, ... )
__attribute__((sentinel));
int vips_bandbool( VipsImage *in, VipsImage **out,
@ -155,6 +169,8 @@ int vips_bandor( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel));
int vips_bandeor( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel));
int vips_bandmean( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel));
int vips_recomb( VipsImage *in, VipsImage **out, VipsImage *m, ... )
__attribute__((sentinel));

View File

@ -41,31 +41,48 @@ extern "C" {
typedef enum {
VIPS_PRECISION_INTEGER,
VIPS_PRECISION_FLOAT,
VIPS_PRECISION_APPROXIMATE
VIPS_PRECISION_APPROXIMATE,
VIPS_PRECISION_LAST
} VipsPrecision;
typedef enum {
VIPS_COMBINE_MAX,
VIPS_COMBINE_SUM,
VIPS_COMBINE_LAST
} VipsCombine;
/**
* VipsOperationMorphology:
* @VIPS_OPERATION_MORPHOLOGY_ERODE: true if all set
* @VIPS_OPERATION_MORPHOLOGY_DILATE: true if one set
*
* More like hit-miss, really.
*
* See also: vips_morph().
*/
typedef enum {
VIPS_OPERATION_MORPHOLOGY_ERODE,
VIPS_OPERATION_MORPHOLOGY_DILATE,
VIPS_OPERATION_MORPHOLOGY_LAST
} VipsOperationMorphology;
int vips_conv( VipsImage *in, VipsImage **out, VipsImage *mask, ... )
__attribute__((sentinel));
int vips_compass( VipsImage *in, VipsImage **out, VipsImage *mask, ... )
__attribute__((sentinel));
int vips_convsep( VipsImage *in, VipsImage **out, VipsImage *mask, ... )
__attribute__((sentinel));
int vips_morph( VipsImage *in, VipsImage **out, VipsImage *mask,
VipsOperationMorphology morph, ... )
__attribute__((sentinel));
void vips_convolution_operation_init( void );
int im_aconvsep( VipsImage *in, VipsImage *out,
DOUBLEMASK *mask, int n_layers );
int im_aconv( VipsImage *in, VipsImage *out,
DOUBLEMASK *mask, int n_layers, int cluster );
int im_conv( VipsImage *in, VipsImage *out, INTMASK *mask );
int im_conv_f( VipsImage *in, VipsImage *out, DOUBLEMASK *mask );
int im_convsep( VipsImage *in, VipsImage *out, INTMASK *mask );
int im_convsep_f( VipsImage *in, VipsImage *out, DOUBLEMASK *mask );
int im_compass( VipsImage *in, VipsImage *out, INTMASK *mask );
int im_gradient( VipsImage *in, VipsImage *out, INTMASK *mask );
int im_lindetect( VipsImage *in, VipsImage *out, INTMASK *mask );
int im_sharpen( VipsImage *in, VipsImage *out,
int mask_size,
double x1, double y2, double y3,
@ -80,8 +97,6 @@ int im_gradcor( VipsImage *in, VipsImage *ref, VipsImage *out );
int im_contrast_surface( VipsImage *in, VipsImage *out,
int half_win_size, int spacing );
int im_addgnoise( VipsImage *in, VipsImage *out, double sigma );
#ifdef __cplusplus
}
#endif /*__cplusplus*/

View File

@ -47,6 +47,10 @@ int vips_xyz( VipsImage **out, int width, int height, ... )
__attribute__((sentinel));
int vips_grey( VipsImage **out, int width, int height, ... )
__attribute__((sentinel));
int vips_gaussmat( VipsImage **out, double sigma, double min_ampl, ... )
__attribute__((sentinel));
int vips_logmat( VipsImage **out, double sigma, double min_ampl, ... )
__attribute__((sentinel));
int vips_text( VipsImage **out, const char *text, ... )
__attribute__((sentinel));

View File

@ -47,6 +47,8 @@ GType vips_align_get_type (void) G_GNUC_CONST;
#define VIPS_TYPE_ALIGN (vips_align_get_type())
GType vips_angle_get_type (void) G_GNUC_CONST;
#define VIPS_TYPE_ANGLE (vips_angle_get_type())
GType vips_angle45_get_type (void) G_GNUC_CONST;
#define VIPS_TYPE_ANGLE45 (vips_angle45_get_type())
/* enumerations from "../../../libvips/include/vips/util.h" */
GType vips_token_get_type (void) G_GNUC_CONST;
#define VIPS_TYPE_TOKEN (vips_token_get_type())
@ -72,6 +74,10 @@ GType vips_operation_flags_get_type (void) G_GNUC_CONST;
/* enumerations from "../../../libvips/include/vips/convolution.h" */
GType vips_precision_get_type (void) G_GNUC_CONST;
#define VIPS_TYPE_PRECISION (vips_precision_get_type())
GType vips_combine_get_type (void) G_GNUC_CONST;
#define VIPS_TYPE_COMBINE (vips_combine_get_type())
GType vips_operation_morphology_get_type (void) G_GNUC_CONST;
#define VIPS_TYPE_OPERATION_MORPHOLOGY (vips_operation_morphology_get_type())
/* enumerations from "../../../libvips/include/vips/object.h" */
GType vips_argument_flags_get_type (void) G_GNUC_CONST;
#define VIPS_TYPE_ARGUMENT_FLAGS (vips_argument_flags_get_type())

View File

@ -83,10 +83,12 @@ int vips_check_8or16( const char *domain, VipsImage *im );
int vips_check_u8or16orf( const char *domain, VipsImage *im );
int vips_check_format_same( const char *domain, VipsImage *im1, VipsImage *im2 );
int vips_check_size_same( const char *domain, VipsImage *im1, VipsImage *im2 );
int vips_check_oddsquare( const char *domain, VipsImage *im );
int vips_check_vector_length( const char *domain, int n, int len );
int vips_check_vector( const char *domain, int n, VipsImage *im );
int vips_check_hist( const char *domain, VipsImage *im );
int vips_check_matrix( const char *domain, VipsImage *im, VipsImage **out );
int vips_check_separable( const char *domain, VipsImage *im );
int vips_check_imask( const char *domain, INTMASK *mask );
int vips_check_dmask( const char *domain, DOUBLEMASK *mask );

View File

@ -421,6 +421,8 @@ int vips_matrixload( const char *filename, VipsImage **out, ... )
__attribute__((sentinel));
int vips_matrixsave( VipsImage *in, const char *filename, ... )
__attribute__((sentinel));
int vips_matrixprint( VipsImage *in, ... )
__attribute__((sentinel));
int vips_magickload( const char *filename, VipsImage **out, ... )
__attribute__((sentinel));

View File

@ -73,9 +73,9 @@ int vips_image_generate( VipsImage *im,
void *a, void *b
);
void vips_demand_hint_array( VipsImage *image,
int vips_image_pipeline_array( VipsImage *image,
VipsDemandStyle hint, VipsImage **in );
void vips_demand_hint( VipsImage *image, VipsDemandStyle hint, ... )
int vips_image_pipelinev( VipsImage *image, VipsDemandStyle hint, ... )
__attribute__((sentinel));
#ifdef __cplusplus

View File

@ -118,11 +118,6 @@ void vips_image_init_fields( VipsImage *image,
VipsInterpretation interpretation,
double xres, double yres );
int vips_image_copy_fields_array( VipsImage *out, VipsImage *in[] );
int vips_image_copy_fieldsv( VipsImage *out, VipsImage *in1, ... )
__attribute__((sentinel));
int vips_image_copy_fields( VipsImage *out, VipsImage *in );
void vips_image_set( VipsImage *image, const char *field, GValue *value );
int vips_image_get( const VipsImage *image,
const char *field, GValue *value_copy );

View File

@ -4,6 +4,9 @@
* - from proto.h
*/
/* All deprecated.
*/
/*
This file is part of VIPS.

View File

@ -31,19 +31,18 @@
*/
#ifndef IM_MORPHOLOGY_H
#define IM_MORPHOLOGY_H
#ifndef VIPS_MORPHOLOGY_H
#define VIPS_MORPHOLOGY_H
#ifdef __cplusplus
extern "C" {
#endif /*__cplusplus*/
int im_dilate( VipsImage *in, VipsImage *out, INTMASK *mask );
int im_erode( VipsImage *in, VipsImage *out, INTMASK *mask );
int im_rank( VipsImage *in, VipsImage *out, int width, int height, int index );
int im_rank_image( VipsImage **in, VipsImage *out, int n, int index );
int im_maxvalue( VipsImage **in, VipsImage *out, int n );
int im_cntlines( VipsImage *im, double *nolines, int flag );
int im_zerox( VipsImage *in, VipsImage *out, int sign );
@ -53,4 +52,4 @@ int im_label_regions( VipsImage *test, VipsImage *mask, int *segments );
}
#endif /*__cplusplus*/
#endif /*IM_MORPHOLOGY_H*/
#endif /*VIPS_MORPHOLOGY_H*/

View File

@ -56,6 +56,11 @@ extern "C" {
*/
#define VIPS_SIZEOF_HEADER (64)
/* Startup plus ABI check.
*/
int vips__init( const char *argv0 );
size_t vips__get_sizeof_vipsobject( void );
/* What we track for each mmap window. Have a list of these on an openin
* VipsImage.
*/
@ -165,6 +170,11 @@ VipsArgumentInstance *vips__argument_get_instance(
VipsArgument *vips__argument_table_lookup( VipsArgumentTable *table,
GParamSpec *pspec);
void vips__demand_hint_array( struct _VipsImage *image,
int hint, struct _VipsImage **in );
int vips__image_copy_fields_array( struct _VipsImage *out,
struct _VipsImage *in[] );
#ifdef __cplusplus
}
#endif /*__cplusplus*/

View File

@ -149,8 +149,20 @@ extern "C" {
#include <vips/almostdeprecated.h>
#include <vips/dispatch.h>
#define vips_init( ARGV0 ) \
(sizeof( VipsObject ) != vips__get_sizeof_vipsobject() ? ( \
vips_info( "vips_init", "%s", _( "ABI mismatch" ) ), \
vips_info( "vips_init", \
_( "library has sizeof(VipsObject) == %zd" ), \
vips__get_sizeof_vipsobject() ), \
vips_info( "vips_init", \
_( "application has sizeof(VipsObject) == %zd" ), \
sizeof( VipsObject() ) ), \
vips_error( "vips_init", "%s", _( "ABI mismatch" ) ), \
-1 ) : \
vips__init( ARGV0 ))
const char *vips_get_argv0( void );
int vips_init( const char *argv0 );
void vips_check_init( void );
void vips_shutdown( void );
GOptionGroup *vips_get_option_group( void );

View File

@ -203,15 +203,17 @@ extern "C" {
#define im_get_argv0 vips_get_argv0
#define im_version_string vips_version_string
#define im_version vips_version
#define im_init_world vips_init
#define im_get_option_group vips_get_option_group
#define im_guess_prefix vips_guess_prefix
#define im_guess_libdir vips_guess_libdir
#define im__global_lock vips__global_lock
#define im_cp_desc vips_image_copy_fields
#define im_cp_descv vips_image_copy_fieldsv
#define im_cp_desc_array vips_image_copy_fields_array
int im_cp_desc(IMAGE *out, IMAGE *in );
int im_cp_descv (IMAGE * im, ...);
#define im_cp_desc_array(I, A) vips__image_copy_fields_array(I, A)
int im_demand_hint (IMAGE * im, VipsDemandStyle hint, ...);
#define im_demand_hint_array( A, B, C ) (vips__demand_hint_array( A, B, C ), 0)
#define im_image vips_image_new_from_memory
#define im_binfile vips_image_new_from_file_raw
#define im__open_temp vips_image_new_temp_file
@ -325,9 +327,6 @@ VipsDemandStyle im_char2dhint( const char *str );
#define im_rect_dup vips_rect_dup
#define im_rect_normalise vips_rect_normalise
int im_demand_hint (IMAGE * im, VipsDemandStyle hint, ...);
#define im_demand_hint_array( A, B, C ) (vips_demand_hint_array( A, B, C ), 0)
#define im_start_one vips_start_one
#define im_stop_one vips_stop_one
#define im_start_many vips_start_many
@ -586,6 +585,8 @@ size_t im_ref_string_get_length( const GValue *value );
#define im_concurrency_set vips_concurrency_set
#define im_concurrency_get vips_concurrency_get
int im_init_world( const char *argv0 );
int im_add( VipsImage *in1, VipsImage *in2, VipsImage *out );
int im_subtract( VipsImage *in1, VipsImage *in2, VipsImage *out );
int im_multiply( VipsImage *in1, VipsImage *in2, VipsImage *out );
@ -711,6 +712,8 @@ int im_rotquad( VipsImage *in, VipsImage *out );
int im_clip2fmt( VipsImage *in, VipsImage *out, VipsBandFormat fmt );
int im_bandjoin( VipsImage *in1, VipsImage *in2, VipsImage *out );
int im_gbandjoin( VipsImage **in, VipsImage *out, int n );
int im_rank_image( VipsImage **in, VipsImage *out, int n, int index );
int im_maxvalue( VipsImage **in, VipsImage *out, int n );
int im_grid( VipsImage *in, VipsImage *out, int tile_height, int across, int down );
int im_scale( VipsImage *in, VipsImage *out );
int im_scaleps( VipsImage *in, VipsImage *out );
@ -768,6 +771,7 @@ int im_blend( VipsImage *c, VipsImage *a, VipsImage *b, VipsImage *out );
DOUBLEMASK *im_vips2mask( VipsImage *in, const char *filename );
INTMASK *im_vips2imask( IMAGE *in, const char *filename );
int im_mask2vips( DOUBLEMASK *in, VipsImage *out );
int im_imask2vips( INTMASK *in, VipsImage *out );
int im_bandmean( VipsImage *in, VipsImage *out );
int im_recomb( VipsImage *in, VipsImage *out, DOUBLEMASK *recomb );
@ -894,6 +898,26 @@ int im_tone_map( VipsImage *in, VipsImage *out, VipsImage *lut );
*/
#define vips_class_map_concrete_all vips_class_map_all
int im_dilate( VipsImage *in, VipsImage *out, INTMASK *mask );
int im_erode( VipsImage *in, VipsImage *out, INTMASK *mask );
int im_aconv( VipsImage *in, VipsImage *out,
DOUBLEMASK *mask, int n_layers, int cluster );
int im_conv( VipsImage *in, VipsImage *out, INTMASK *mask );
int im_conv_f( VipsImage *in, VipsImage *out, DOUBLEMASK *mask );
int im_aconvsep( VipsImage *in, VipsImage *out,
DOUBLEMASK *mask, int n_layers );
int im_convsep( VipsImage *in, VipsImage *out, INTMASK *mask );
int im_convsep_f( VipsImage *in, VipsImage *out, DOUBLEMASK *mask );
int im_compass( VipsImage *in, VipsImage *out, INTMASK *mask );
int im_gradient( VipsImage *in, VipsImage *out, INTMASK *mask );
int im_lindetect( VipsImage *in, VipsImage *out, INTMASK *mask );
int im_addgnoise( VipsImage *in, VipsImage *out, double sigma );
#ifdef __cplusplus
}
#endif /*__cplusplus*/

View File

@ -50,6 +50,7 @@ vips_scan_headers = \
${top_srcdir}/libvips/include/vips/colour.h \
${top_srcdir}/libvips/include/vips/operation.h \
${top_srcdir}/libvips/include/vips/convolution.h \
${top_srcdir}/libvips/include/vips/morphology.h \
${top_srcdir}/libvips/include/vips/object.h
enumtypes.c: $(vips_scan_headers) Makefile

View File

@ -223,6 +223,30 @@ vips_angle_get_type( void )
return( etype );
}
GType
vips_angle45_get_type( void )
{
static GType etype = 0;
if( etype == 0 ) {
static const GEnumValue values[] = {
{VIPS_ANGLE45_0, "VIPS_ANGLE45_0", "0"},
{VIPS_ANGLE45_45, "VIPS_ANGLE45_45", "45"},
{VIPS_ANGLE45_90, "VIPS_ANGLE45_90", "90"},
{VIPS_ANGLE45_135, "VIPS_ANGLE45_135", "135"},
{VIPS_ANGLE45_180, "VIPS_ANGLE45_180", "180"},
{VIPS_ANGLE45_225, "VIPS_ANGLE45_225", "225"},
{VIPS_ANGLE45_270, "VIPS_ANGLE45_270", "270"},
{VIPS_ANGLE45_315, "VIPS_ANGLE45_315", "315"},
{VIPS_ANGLE45_LAST, "VIPS_ANGLE45_LAST", "last"},
{0, NULL, NULL}
};
etype = g_enum_register_static( "VipsAngle45", values );
}
return( etype );
}
/* enumerations from "../../libvips/include/vips/arithmetic.h" */
GType
vips_operation_math_get_type( void )
@ -601,6 +625,7 @@ vips_precision_get_type( void )
{VIPS_PRECISION_INTEGER, "VIPS_PRECISION_INTEGER", "integer"},
{VIPS_PRECISION_FLOAT, "VIPS_PRECISION_FLOAT", "float"},
{VIPS_PRECISION_APPROXIMATE, "VIPS_PRECISION_APPROXIMATE", "approximate"},
{VIPS_PRECISION_LAST, "VIPS_PRECISION_LAST", "last"},
{0, NULL, NULL}
};
@ -609,6 +634,42 @@ vips_precision_get_type( void )
return( etype );
}
GType
vips_combine_get_type( void )
{
static GType etype = 0;
if( etype == 0 ) {
static const GEnumValue values[] = {
{VIPS_COMBINE_MAX, "VIPS_COMBINE_MAX", "max"},
{VIPS_COMBINE_SUM, "VIPS_COMBINE_SUM", "sum"},
{VIPS_COMBINE_LAST, "VIPS_COMBINE_LAST", "last"},
{0, NULL, NULL}
};
etype = g_enum_register_static( "VipsCombine", values );
}
return( etype );
}
GType
vips_operation_morphology_get_type( void )
{
static GType etype = 0;
if( etype == 0 ) {
static const GEnumValue values[] = {
{VIPS_OPERATION_MORPHOLOGY_ERODE, "VIPS_OPERATION_MORPHOLOGY_ERODE", "erode"},
{VIPS_OPERATION_MORPHOLOGY_DILATE, "VIPS_OPERATION_MORPHOLOGY_DILATE", "dilate"},
{VIPS_OPERATION_MORPHOLOGY_LAST, "VIPS_OPERATION_MORPHOLOGY_LAST", "last"},
{0, NULL, NULL}
};
etype = g_enum_register_static( "VipsOperationMorphology", values );
}
return( etype );
}
/* enumerations from "../../libvips/include/vips/object.h" */
GType
vips_argument_flags_get_type( void )

View File

@ -1012,6 +1012,32 @@ vips_check_size_same( const char *domain, VipsImage *im1, VipsImage *im2 )
return( 0 );
}
/**
* vips_check_oddsquare:
* @domain: the originating domain for the error message
* @im: image to check
*
* Check that the image is square and that the sides are odd.
* If not, set an error message
* and return non-zero.
*
* See also: vips_error().
*
* Returns: 0 if OK, -1 otherwise.
*/
int
vips_check_oddsquare( const char *domain, VipsImage *im )
{
if( im->Xsize != im->Ysize ||
im->Xsize % 2 == 0 ) {
vips_error( domain,
"%s", _( "images must be odd and square" ) );
return( -1 );
}
return( 0 );
}
/**
* vips_check_bands_same:
* @domain: the originating domain for the error message
@ -1240,6 +1266,33 @@ vips_check_matrix( const char *domain, VipsImage *im, VipsImage **out )
return( 0 );
}
/**
* vips_check_separable:
* @domain: the originating domain for the error message
* @im: image to check
*
* Separable matrix images must have width or height 1.
* Return 0 if the image will pass, or -1 and
* set an error message otherwise.
*
* See also: vips_error().
*
* Returns: 0 if OK, -1 otherwise.
*/
int
vips_check_separable( const char *domain, VipsImage *im )
{
if( im->Xsize != 1 &&
im->Ysize != 1 ) {
vips_error( domain,
"%s", _( "separable matrix images must have "
"width or height 1" ) );
return( -1 );
}
return( 0 );
}
/**
* vips_check_imask: (skip)
* @domain: the originating domain for the error message

View File

@ -274,26 +274,12 @@ vips__link_map( VipsImage *image, gboolean upstream,
return( result );
}
/**
* vips_demand_hint_array:
* @image: 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
* %VIPS_DEMAND_STYLE_SMALLTILE, operations which work on local windows of
* pixels will like %VIPS_DEMAND_STYLE_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 vips_demand_hint().
*
* See also: vips_demand_hint(), vips_image_generate().
/* We have to have this as a separate entry point so we can support the old
* vips7 API.
*/
void
vips_demand_hint_array( VipsImage *image, VipsDemandStyle hint, VipsImage **in )
vips__demand_hint_array( VipsImage *image,
VipsDemandStyle hint, VipsImage **in )
{
int i, len, nany;
VipsDemandStyle set_hint;
@ -327,7 +313,7 @@ vips_demand_hint_array( VipsImage *image, VipsDemandStyle hint, VipsImage **in )
image->dhint = set_hint;
#ifdef DEBUG
printf( "vips_demand_hint_array: set dhint for \"%s\" to %s\n",
printf( "vips_image_pipeline_array: set dhint for \"%s\" to %s\n",
image->filename,
vips_enum_nick( VIPS_TYPE_DEMAND_STYLE, image->dhint ) );
printf( "\toperation requested %s\n",
@ -354,17 +340,62 @@ vips_demand_hint_array( VipsImage *image, VipsDemandStyle hint, VipsImage **in )
}
/**
* vips_demand_hint:
* @image: image to set hint for
* @hint: hint for this image
* @Varargs: %NULL-terminated list of input images to this operation
* vips_image_pipeline_array:
* @image: output image
* @hint: demand hint for @image
* @in: %NULL-terminated array of input images
*
* Build an array and call vips_demand_hint_array().
* Add an image to a pipeline. @image depends on all of the images in @in,
* @image prefers to supply pixels according to @hint.
*
* See also: vips_demand_hint(), vips_image_generate().
* 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
* %VIPS_DEMAND_STYLE_SMALLTILE, operations which work on local windows of
* pixels will like %VIPS_DEMAND_STYLE_FATSTRIP.
*
* Header fields in @image are set from the fields in @in, with lower-numbered
* images in @in taking priority.
* For example, if @in[0] and @in[1] both have an item
* called "icc-profile", it's the profile attached to @in[0] that will end up
* on @image.
* Image history is completely copied from all @in. @image will have the history
* of all the input images.
* The array of input images can be empty, meaning @image is at the start of a
* pipeline.
*
* VIPS uses the list of input images to build the tree of operations it needs
* for the cache invalidation system.
*
* See also: vips_image_pipelinev(), vips_image_generate().
*
* Returns: 0 on success, -1 on error.
*/
void
vips_demand_hint( VipsImage *image, VipsDemandStyle hint, ... )
int
vips_image_pipeline_array( VipsImage *image,
VipsDemandStyle hint, VipsImage **in )
{
vips__demand_hint_array( image, hint, in );
if( in[0] &&
vips__image_copy_fields_array( image, in ) )
return( -1 );
return( 0 );
}
/**
* vips_image_pipelinev:
* @image: output image of pipeline
* @hint: hint for this image
* @...: %NULL-terminated list of input images
*
* Build an array and call vips_image_pipeline_array().
*
* See also: vips_image_generate().
*/
int
vips_image_pipelinev( VipsImage *image, VipsDemandStyle hint, ... )
{
va_list ap;
int i;
@ -376,14 +407,14 @@ vips_demand_hint( VipsImage *image, VipsDemandStyle hint, ... )
;
va_end( ap );
if( i == MAX_IMAGES ) {
vips_warn( "vips_demand_hint", "%s", _( "too many images" ) );
vips_warn( "vips_image_pipeline", "%s", _( "too many images" ) );
/* Make sure we have a sentinel there.
*/
ar[i - 1] = NULL;
}
vips_demand_hint_array( image, hint, ar );
return( vips_image_pipeline_array( image, hint, ar ) );
}
/**

View File

@ -604,13 +604,13 @@ vips_image_get_data( VipsImage *image )
* @yres: vertical resolution, pixels per millimetre
*
* A convenience function to set the header fields after creating an image.
* Normally you copy the fields from one of your input images with
* vips_image_copy_fields() and then make
* Normally you copy the fields from your input images with
* vips_image_pipelinev() and then make
* any adjustments you need, but if you are creating an image from scratch,
* for example im_black() or im_jpeg2vips(), you do need to set all the
* fields yourself.
*
* See also: vips_image_copy_fields().
* See also: vips_image_pipelinev().
*/
void
vips_image_init_fields( VipsImage *image,
@ -655,7 +655,7 @@ meta_cp_field( VipsMeta *meta, VipsImage *dst )
return( NULL );
}
/* Copy meta on to dst. Called from vips_cp_desc().
/* Copy meta on to dst.
*/
static int
meta_cp( VipsImage *dst, const VipsImage *src )
@ -671,31 +671,11 @@ meta_cp( VipsImage *dst, const VipsImage *src )
return( 0 );
}
/**
* vips_image_copy_fields_array:
* @out: image to copy to
* @in: %NULL-terminated array of images to copy from
*
* Copy fields from all the input images to the output image. There must be at
* least one input image.
*
* The first input image is used to set the main fields of @out (@width,
* @coding and so on).
*
* Metadata from all the images is merged on to @out, with lower-numbered items
* overriding higher. So for example, if @in[0] and @in[1] both have an item
* called "icc-profile", it's the profile attached to @in[0] that will end up
* on @out.
*
* Image history is completely copied from all @in. @out will have the history
* of all the input images.
*
* See also: vips_image_copy_fieldsv(), vips_image_copy_fields().
*
* Returns: 0 on success, -1 on error.
/* We have to have this as a separate entry point so we can support the old
* vips7 API.
*/
int
vips_image_copy_fields_array( VipsImage *out, VipsImage *in[] )
vips__image_copy_fields_array( VipsImage *out, VipsImage *in[] )
{
int i;
int ni;
@ -740,63 +720,6 @@ vips_image_copy_fields_array( VipsImage *out, VipsImage *in[] )
return( 0 );
}
/* Max number of images we can handle.
*/
#define MAX_IMAGES (1000)
/**
* vips_image_copy_fieldsv:
* @out: image to copy to
* @in1: first image to copy from
* @Varargs: %NULL-terminated list of images to copy from
*
* Copy fields from all the input images to the output image. A convenience
* function over vips_image_copy_fields_array().
*
* See also: vips_image_copy_fields_array(), vips_image_copy_fields().
*
* Returns: 0 on success, -1 on error.
*/
int
vips_image_copy_fieldsv( VipsImage *out, VipsImage *in1, ... )
{
va_list ap;
int i;
VipsImage *in[MAX_IMAGES];
in[0] = in1;
va_start( ap, in1 );
for( i = 1; i < MAX_IMAGES &&
(in[i] = va_arg( ap, VipsImage * )); i++ )
;
va_end( ap );
if( i == MAX_IMAGES ) {
vips_error( "vips_image_copy_fieldsv",
"%s", _( "too many images" ) );
return( -1 );
}
return( vips_image_copy_fields_array( out, in ) );
}
/**
* vips_image_copy_fields:
* @out: image to copy to
* @in: image to copy from
*
* Copy fields from @in to @out. A convenience
* function over vips_image_copy_fields_array().
*
* See also: vips_image_copy_fields_array(), vips_image_copy_fieldsv().
*
* Returns: 0 on success, -1 on error.
*/
int
vips_image_copy_fields( VipsImage *out, VipsImage *in )
{
return( vips_image_copy_fieldsv( out, in, NULL ) );
}
/**
* vips_image_set:
* @image: image to set the metadata on

View File

@ -105,7 +105,7 @@
* @VIPS_DEMAND_STYLE_THINSTRIP: demand in thin (typically 1 pixel high) strips
* @VIPS_DEMAND_STYLE_ANY: demand geometry does not matter
*
* See vips_demand_hint(). Operations can hint to the VIPS image IO system about
* See vips_image_pipelinev(). Operations can hint to the VIPS image IO system about
* the kind of demand geometry they prefer.
*
* These demand styles are given below in order of increasing
@ -134,7 +134,7 @@
* file (even indirectly) so any demand style is OK. It's used for things like
* im_black() where the pixels are calculated.
*
* See also: vips_demand_hint().
* See also: vips_image_pipelinev().
*/
/**
@ -1939,10 +1939,9 @@ int
vips_image_write( VipsImage *image, VipsImage *out )
{
if( vips_image_pio_input( image ) ||
vips_image_copy_fields( out, image ) )
vips_image_pipelinev( out,
VIPS_DEMAND_STYLE_THINSTRIP, image, NULL ) )
return( -1 );
vips_demand_hint( out,
VIPS_DEMAND_STYLE_THINSTRIP, image, NULL );
/* We generate from @image partially, so we need to keep it about as
* long as @out is about.
@ -2358,7 +2357,7 @@ int
vips__image_wio_output( VipsImage *image )
{
#ifdef DEBUG_IO
printf( "vips_image_wio_output: WIO output for %s\n",
printf( "vips__image_wio_output: WIO output for %s\n",
image->filename );
#endif/*DEBUG_IO*/
@ -2367,7 +2366,7 @@ vips__image_wio_output( VipsImage *image )
/* Make sure nothing is attached.
*/
if( image->generate_fn ) {
vips_error( "vips_image_wio_output",
vips_error( "vips__image_wio_output",
"%s", _( "image already written" ) );
return( -1 );
}
@ -2391,7 +2390,7 @@ vips__image_wio_output( VipsImage *image )
break;
default:
vips_error( "vips_image_wio_output",
vips_error( "vips__image_wio_output",
"%s", _( "image not writeable" ) );
return( -1 );
}

View File

@ -140,7 +140,7 @@ vips_get_argv0( void )
* </para>
* </listitem>
* <listitem>
* <para>loads any plugins from $libdir/vips-x.y, where x and y are the
* <para>loads any plugins from $libdir/vips-x.y/, where x and y are the
* major and minor version numbers for this VIPS.
* </para>
* </listitem>
@ -165,8 +165,13 @@ vips_get_argv0( void )
*
* Returns: 0 on success, -1 otherwise
*/
/* vips_init() is actually a macro which checks library and application
* compatibility before calling vips__init().
*/
int
vips_init( const char *argv0 )
vips__init( const char *argv0 )
{
extern GType vips_system_get_type( void );
@ -299,6 +304,20 @@ vips_init( const char *argv0 )
return( 0 );
}
/* Return the sizeof() various important data structures. These are checked
* against the headers used to build our caller by vips_init().
*
* We allow direct access to members of VipsImage and VipsRegion (mostly for
* reasons of history), so any change to a superclass of either of these
* objects will break our ABI.
*/
size_t
vips__get_sizeof_vipsobject( void )
{
return( sizeof( VipsObject ) );
}
/* Call this before vips stuff that uses stuff we need to have inited.
*/
void

Some files were not shown because too many files have changed in this diff Show More