Merge remote-tracking branch 'origin/master' into draw

This commit is contained in:
John Cupitt 2014-02-03 14:33:34 +00:00
commit 87ab32d422
62 changed files with 798 additions and 321 deletions

View File

@ -1,4 +1,16 @@
21/1/14 started 7.39.0
- auto-decode for (almost) all operations
- background render thread cleans up and quits neatly
- colourspace has a source_space option
- operations can be tagged as "deprecated"
22/1/14 started 7.38.2
- auto RAD decode for affine
- falsecolour was not working for some image types
- foreign memory buffer images did not have the right dhint, broke
command-line falsecolour on sequential images
- support many Radiance readers active at once
- add secret "rgbjpeg" flag to vips_tiffsave() to help IIP
19/1/14 started 7.38.1
- bump soname, thanks benjamin

View File

@ -189,7 +189,7 @@ OpenEXR images.
## OpenSlide
If available, libvips can load OpenSlide-supported virtual slide
files: Aperio, Hamamatsu VMS and VMU, Leica, MIRAX, and Trestle.
files: Aperio, Hamamatsu, Leica, MIRAX, Sakura, Trestle, and Ventana.
## swig, python, python-dev

22
TODO
View File

@ -1,3 +1,21 @@
- check_uncoded() left to do:
resample/quadratic.c
- move vips__image_decode() into the public API
- we vips_image_write() a lot, could we do this by
int
vips_image_write( in, out )
{
g_object_ref( in)
vips_object_local( out,in )
}
i.e. do everything at pipe build time
- inplace
can we set a region for the pixels we will modify?
@ -5,7 +23,6 @@
is there any point doing this? only useful on 32-bit machines, which
don't really exist any more
- need to do mosaicing and inplace, plus im_label_regions in morph
- now vips_linear() has uchar output, can we do something with orc?
@ -22,8 +39,7 @@
interpolator would need to be built for the bands / stride / type of the
image
need new API For this, since interpolators currently work for any image
need new API For this since interpolators currently work for any image
- vips_gaussblur() should switch to float prec if given a float image?

View File

@ -497,12 +497,19 @@ AC_ARG_WITH([openslide],
AS_HELP_STRING([--without-openslide], [build without OpenSlide (default: test)]))
if test x"$with_openslide" != x"no"; then
PKG_CHECK_MODULES(OPENSLIDE, openslide >= 3.3.0,
[AC_DEFINE(HAVE_OPENSLIDE,1,[define if you have OpenSlide >= 3.3.0 installed.])
PKG_CHECK_MODULES(OPENSLIDE, [openslide >= 3.4.0],
[AC_DEFINE(HAVE_OPENSLIDE_3_4,1,[define if you have OpenSlide >= 3.4.0 installed.])
AC_DEFINE(HAVE_OPENSLIDE,1,[define if you have OpenSlide >= 3.3.0 installed.])
with_openslide=yes
PACKAGES_USED="$PACKAGES_USED openslide"],
[AC_MSG_WARN([OpenSlide >= 3.3.0 not found; disabling virtual slide support])
with_openslide=no
[AC_MSG_NOTICE([OpenSlide >= 3.4.0 not found; checking for >= 3.3.0])
PKG_CHECK_MODULES(OPENSLIDE, [openslide >= 3.3.0],
[AC_DEFINE(HAVE_OPENSLIDE,1,[define if you have OpenSlide >= 3.3.0 installed.])
with_openslide=yes
PACKAGES_USED="$PACKAGES_USED openslide"],
[AC_MSG_WARN([OpenSlide >= 3.3.0 not found; disabling virtual slide support])
with_openslide=no
])
])
fi

View File

@ -45,7 +45,7 @@
init7
Memcheck:Leak
...
fun:g_malloc0
fun:*alloc*
...
fun:_dl_init
}
@ -85,13 +85,29 @@
fun:XInitExtension
}
{
gio
Memcheck:Leak
fun:malloc
...
fun:g_simple_async_result_complete
}
{
pthread
Memcheck:Leak
fun:calloc
fun:_dl_allocate_tls
fun:pthread_create@@GLIBC_*
}
# hide all dbus reports, not the app's problem
{
dbus
Memcheck:Leak
fun:*alloc
...
obj:/lib/libdbus-1.so.*
obj:*/libdbus-1.so.*
}
# hide all orbit leaks, not our problem
@ -112,6 +128,31 @@
fun:FcConfigParseAndLoad
}
{
fontconfig2
Memcheck:Leak
fun:malloc
fun:strdup
fun:FcValueSave
obj:*/libfontconfig.so.*
}
{
fontconfig3
Memcheck:Leak
fun:realloc
...
fun:FcFontMatch
}
{
fontconfig4
Memcheck:Leak
fun:realloc
...
fun:FcPatternAddInteger
}
{
freetype_init
Memcheck:Leak
@ -120,6 +161,14 @@
fun:FT_Open_Face
}
{
harfbuzz
Memcheck:Leak
fun:calloc
...
fun:hb_shape_plan_execute
}
{
goffice_init
Memcheck:Leak
@ -257,8 +306,6 @@
fun:write_vips
}
# ubuntu 13.04 suppressions
{
pixman1
Memcheck:Cond
@ -272,6 +319,30 @@
fun:rsvg_cairo_surface_to_pixbuf
}
{
rsvg
Memcheck:Cond
obj:*/librsvg-2.so.*
}
{
murrine
Memcheck:Leak
fun:calloc
fun:g_malloc0
fun:raico_blur_create
}
{
signal_connect
Memcheck:Leak
fun:calloc
fun:g_malloc0
fun:g_closure_new_simple
fun:g_cclosure_new
fun:g_signal_connect_data
}
# ruby has some annoying ones too
{
@ -304,3 +375,4 @@

View File

@ -51,6 +51,7 @@
#include <math.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include "parithmetic.h"
@ -500,6 +501,7 @@ vips_arithmetic_build( VipsObject *object )
VipsArithmetic *arithmetic = VIPS_ARITHMETIC( object );
VipsArithmeticClass *aclass = VIPS_ARITHMETIC_GET_CLASS( arithmetic );
VipsImage **decode;
VipsImage **format;
VipsImage **band;
VipsImage **size;
@ -524,12 +526,9 @@ vips_arithmetic_build( VipsObject *object )
"%s", _( "too many input images" ) );
return( -1 );
}
for( i = 0; i < arithmetic->n; i++ )
if( vips_image_pio_input( arithmetic->in[i] ) ||
vips_check_uncoded( class->nickname,
arithmetic->in[i] ) )
return( -1 );
decode = (VipsImage **)
vips_object_local_array( object, arithmetic->n );
format = (VipsImage **)
vips_object_local_array( object, arithmetic->n );
band = (VipsImage **)
@ -537,9 +536,15 @@ vips_arithmetic_build( VipsObject *object )
size = (VipsImage **)
vips_object_local_array( object, arithmetic->n );
/* Decode RAD/LABQ etc.
*/
for( i = 0; i < arithmetic->n; i++ )
if( vips__image_decode( arithmetic->in[i], &decode[i] ) )
return( -1 );
/* Cast our input images up to a common format, bands and size.
*/
if( vips__formatalike_vec( arithmetic->in, format, arithmetic->n ) ||
if( vips__formatalike_vec( decode, format, arithmetic->n ) ||
vips__bandalike_vec( class->nickname,
format, band, arithmetic->n, arithmetic->base_bands ) ||
vips__sizealike_vec( band, size, arithmetic->n ) )

View File

@ -492,7 +492,7 @@ vips_complex2_class_init( VipsComplex2Class *class )
object_class->nickname = "complex2";
object_class->description =
_( "perform a binary complex operation on two images" );
_( "complex binary operations on two images" );
aclass->process_line = vips_complex2_buffer;

View File

@ -210,7 +210,7 @@ vips_deviate_class_init( VipsDeviateClass *class )
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "deviate";
object_class->description = _( "find image average" );
object_class->description = _( "find image standard deviation" );
object_class->build = vips_deviate_build;
sclass->start = vips_deviate_start;

View File

@ -130,7 +130,7 @@ vips_hist_find_indexed_build( VipsObject *object )
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsStatistic *statistic = VIPS_STATISTIC( object );
VipsHistFindIndexed *indexed = (VipsHistFindIndexed *) object;
VipsImage **t = (VipsImage **) vips_object_local_array( object, 1 );
VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 );
g_object_set( object,
"out", vips_image_new(),

View File

@ -286,7 +286,7 @@ vips_hist_find_ndim_class_init( VipsHistFindNDimClass *class )
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "hist_find_ndim";
object_class->description = _( "find image histogram" );
object_class->description = _( "find n-dimensional image histogram" );
object_class->build = vips_hist_find_ndim_build;
sclass->start = vips_hist_find_ndim_start;

View File

@ -122,8 +122,22 @@ vips_linear_build( VipsObject *object )
VipsUnary *unary = (VipsUnary *) object;
VipsLinear *linear = (VipsLinear *) object;
int bands;
int i;
/* How many bands will our input image have after decoding?
*/
switch( unary->in->Coding ) {
case VIPS_CODING_RAD:
case VIPS_CODING_LABQ:
bands = 3;
break;
default:
bands = unary->in->Bands;
break;
}
/* If we have a three-element vector we need to bandup the image to
* match.
*/
@ -133,7 +147,7 @@ vips_linear_build( VipsObject *object )
if( linear->b )
linear->n = VIPS_MAX( linear->n, linear->b->n );
if( unary->in )
linear->n = VIPS_MAX( linear->n, unary->in->Bands );
linear->n = VIPS_MAX( linear->n, bands );
arithmetic->base_bands = linear->n;
if( unary->in && linear->a && linear->b ) {

View File

@ -196,7 +196,7 @@ vips_math_class_init( VipsMathClass *class )
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "math";
object_class->description = _( "perform a math function on an image" );
object_class->description = _( "apply a math operation to an image" );
object_class->build = vips_math_build;
aclass->process_line = vips_math_buffer;

View File

@ -216,8 +216,7 @@ vips_relational_class_init( VipsRelationalClass *class )
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "relational";
object_class->description =
_( "a relational operation on a pair of images" );
object_class->description = _( "relational operation on two images" );
object_class->build = vips_relational_build;
aclass->process_line = vips_relational_buffer;

View File

@ -50,6 +50,7 @@
#include <vips/vips.h>
#include <vips/debug.h>
#include <vips/internal.h>
#include "statistic.h"
@ -109,9 +110,7 @@ vips_statistic_build( VipsObject *object )
{
VipsStatistic *statistic = VIPS_STATISTIC( object );
VipsStatisticClass *sclass = VIPS_STATISTIC_GET_CLASS( statistic );
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
const char *domain = class->nickname;
VipsImage **t = (VipsImage **) vips_object_local_array( object, 1 );
VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 );
#ifdef DEBUG
printf( "vips_statistic_build: " );
@ -122,20 +121,20 @@ vips_statistic_build( VipsObject *object )
if( VIPS_OBJECT_CLASS( vips_statistic_parent_class )->build( object ) )
return( -1 );
statistic->ready = statistic->in;
if( vips__image_decode( statistic->ready, &t[0] ) )
return( -1 );
statistic->ready = t[0];
/* If there's a format table, cast the input.
*/
if( sclass->format_table ) {
if( vips_cast( statistic->in, &t[0],
if( vips_cast( statistic->ready, &t[1],
sclass->format_table[statistic->in->BandFmt], NULL ) )
return( -1 );
statistic->ready = t[0];
statistic->ready = t[1];
}
else
statistic->ready = statistic->in;
if( vips_image_pio_input( statistic->ready ) ||
vips_check_uncoded( domain, statistic->ready ) )
return( -1 );
if( vips_sink( statistic->ready,
vips_statistic_scan_start,

View File

@ -627,30 +627,18 @@ vips_colour_difference_build( VipsObject *object )
right = difference->right;
extra = NULL;
/* Unpack LABQ images,
*/
if( left &&
left->Coding == VIPS_CODING_LABQ ) {
if( vips_LabQ2Lab( left, &t[0], NULL ) )
if( left ) {
if( vips__image_decode( left, &t[0] ) )
return( -1 );
left = t[0];
}
if( right &&
right->Coding == VIPS_CODING_LABQ ) {
if( vips_LabQ2Lab( right, &t[1], NULL ) )
if( right ) {
if( vips__image_decode( right, &t[1] ) )
return( -1 );
right = t[1];
}
if( left &&
vips_check_uncoded( VIPS_OBJECT_CLASS( class )->nickname,
left ) )
return( -1 );
if( right &&
vips_check_uncoded( VIPS_OBJECT_CLASS( class )->nickname,
right ) )
return( -1 );
/* Detach and reattach extra bands, if any. If both left and right
* have extra bands, give up.
*/

View File

@ -8,6 +8,8 @@
* - add RGB16 as a source
* 19/1/14
* - auto-decode RAD images
* 3/2/14
* - add "source_space", overrides source space guess
*/
/*
@ -388,6 +390,7 @@ typedef struct _VipsColourspace {
VipsImage *in;
VipsImage *out;
VipsInterpretation space;
VipsInterpretation source_space;
} VipsColourspace;
typedef VipsOperationClass VipsColourspaceClass;
@ -408,7 +411,6 @@ vips_colourspace_build( VipsObject *object )
VipsInterpretation interpretation;
/* Verify that all input args have been set.
*/
if( VIPS_OBJECT_CLASS( vips_colourspace_parent_class )->
@ -426,7 +428,10 @@ vips_colourspace_build( VipsObject *object )
x = t[0];
}
interpretation = vips_image_guess_interpretation( x );
if( vips_object_argument_isset( object, "source_space" ) )
interpretation = colourspace->source_space;
else
interpretation = vips_image_guess_interpretation( x );
/* Treat RGB and RGB16 as sRGB. If you want some other treatment,
* you'll need to use the icc funcs.
@ -506,11 +511,20 @@ vips_colourspace_class_init( VipsColourspaceClass *class )
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsColourspace, space ),
VIPS_TYPE_INTERPRETATION, VIPS_INTERPRETATION_sRGB );
VIPS_ARG_ENUM( class, "source-space", 6,
_( "Source space" ),
_( "Source colour space" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsColourspace, source_space ),
VIPS_TYPE_INTERPRETATION, VIPS_INTERPRETATION_sRGB );
}
static void
vips_colourspace_init( VipsColourspace *colourspace )
{
colourspace->source_space = VIPS_INTERPRETATION_sRGB;
}
/**
@ -519,7 +533,12 @@ vips_colourspace_init( VipsColourspace *colourspace )
* @out: output image
* @space: convert to this colour space
*
* This operation looks at the interpretation field of @in and runs
* Optional arguments:
*
* @source_space: input colour space
*
* This operation looks at the interpretation field of @in (or uses
* @source_space, if set) and runs
* a set of colourspace conversion functions to move it to @space.
*
* For example, given an image tagged as #VIPS_INTERPRETATION_YXY, running

View File

@ -123,6 +123,7 @@ vips_bandary_build( VipsObject *object )
VipsBandary *bandary = (VipsBandary *) object;
int i;
VipsImage **decode;
VipsImage **format;
VipsImage **size;
@ -139,14 +140,15 @@ vips_bandary_build( VipsObject *object )
"%s", _( "too many input images" ) );
return( -1 );
}
for( i = 0; i < bandary->n; i++ )
if( vips_image_pio_input( bandary->in[i] ) ||
vips_check_uncoded( class->nickname, bandary->in[i] ) )
return( -1 );
decode = (VipsImage **) vips_object_local_array( object, bandary->n );
format = (VipsImage **) vips_object_local_array( object, bandary->n );
size = (VipsImage **) vips_object_local_array( object, bandary->n );
if( vips__formatalike_vec( bandary->in, format, bandary->n ) ||
for( i = 0; i < bandary->n; i++ )
if( vips__image_decode( bandary->in[i], &decode[i] ) )
return( -1 );
if( vips__formatalike_vec( decode, format, bandary->n ) ||
vips__sizealike_vec( format, size, bandary->n ) )
return( -1 );
bandary->ready = size;

View File

@ -429,36 +429,41 @@ vips_cast_gen( VipsRegion *or, void *vseq, void *a, void *b,
static int
vips_cast_build( VipsObject *object )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsConversion *conversion = VIPS_CONVERSION( object );
VipsCast *cast = (VipsCast *) object;
VipsImage **t = (VipsImage **)
vips_object_local_array( object, 2 );
VipsImage *in;
if( VIPS_OBJECT_CLASS( vips_cast_parent_class )->build( object ) )
return( -1 );
in = cast->in;
/* Trivial case: fall back to copy().
*/
if( cast->in->BandFmt == cast->format )
return( vips_image_write( cast->in, conversion->out ) );
if( in->BandFmt == cast->format )
return( vips_image_write( in, conversion->out ) );
if( vips_check_uncoded( class->nickname, cast->in ) ||
vips_image_pio_input( cast->in ) )
if( vips__image_decode( in, &t[0] ) )
return( -1 );
in = t[0];
if( vips_image_pipelinev( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, cast->in, NULL ) )
VIPS_DEMAND_STYLE_THINSTRIP, in, NULL ) )
return( -1 );
conversion->out->BandFmt = cast->format;
g_signal_connect( cast->in, "preeval",
g_signal_connect( in, "preeval",
G_CALLBACK( vips_cast_preeval ), cast );
g_signal_connect( cast->in, "posteval",
g_signal_connect( in, "posteval",
G_CALLBACK( vips_cast_posteval ), cast );
if( vips_image_generate( conversion->out,
vips_cast_start, vips_cast_gen, vips_cast_stop,
cast->in, cast ) )
in, cast ) )
return( -1 );
return( 0 );

View File

@ -14,6 +14,8 @@
* - force input to mono 8-bit for the user
* 1/8/13
* - redone as a class
* 23/1/14
* - oops, was not auto-getting and casting the first band
*/
/*
@ -52,6 +54,7 @@
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include "pconversion.h"
@ -329,10 +332,9 @@ static unsigned char vips_falsecolour_pet[][3] = {
static int
vips_falsecolour_build( VipsObject *object )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsConversion *conversion = VIPS_CONVERSION( object );
VipsFalsecolour *falsecolour = (VipsFalsecolour *) object;
VipsImage **t = (VipsImage **) vips_object_local_array( object, 4 );
VipsImage **t = (VipsImage **) vips_object_local_array( object, 5 );
if( VIPS_OBJECT_CLASS( vips_falsecolour_parent_class )->
build( object ) )
@ -343,13 +345,15 @@ vips_falsecolour_build( VipsObject *object )
VIPS_FORMAT_UCHAR )) )
return( -1 );
/* Force to mono 8-bit.
/* Force to mono 8-bit. Don't use vips_colourspace() to go to B_W, we
* want to work for images which aren't in a recognised space, like
* MULTIBAND.
*/
if( vips_check_uncoded( class->nickname, falsecolour->in ) ||
vips_extract_band( falsecolour->in, &t[1], 0, NULL ) ||
vips_cast( t[1], &t[2], VIPS_FORMAT_UCHAR, NULL ) ||
vips_maplut( falsecolour->in, &t[3], t[0], NULL ) ||
vips_image_write( t[3], conversion->out ) )
if( vips__image_decode( falsecolour->in, &t[1] ) ||
vips_extract_band( t[1], &t[2], 0, NULL ) ||
vips_cast( t[2], &t[3], VIPS_FORMAT_UCHAR, NULL ) ||
vips_maplut( t[3], &t[4], t[0], NULL ) ||
vips_image_write( t[4], conversion->out ) )
return( -1 );
return( 0 );

View File

@ -300,24 +300,31 @@ vips_flatten_build( VipsObject *object )
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsConversion *conversion = VIPS_CONVERSION( object );
VipsFlatten *flatten = (VipsFlatten *) object;
VipsImage **t = (VipsImage **) vips_object_local_array( object, 1 );
VipsImage *in;
int i;
gboolean black;
if( VIPS_OBJECT_CLASS( vips_flatten_parent_class )->build( object ) )
return( -1 );
in = flatten->in;
if( vips__image_decode( in, &t[0] ) )
return( -1 );
in = t[0];
/* Trivial case: fall back to copy().
*/
if( flatten->in->Bands == 1 )
return( vips_image_write( flatten->in, conversion->out ) );
return( vips_image_write( in, conversion->out ) );
if( vips_check_uncoded( class->nickname, flatten->in ) ||
vips_check_noncomplex( class->nickname, flatten->in ) ||
vips_image_pio_input( flatten->in ) )
if( vips_check_noncomplex( class->nickname, in ) )
return( -1 );
if( vips_image_pipelinev( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, flatten->in, NULL ) )
VIPS_DEMAND_STYLE_THINSTRIP, in, NULL ) )
return( -1 );
conversion->out->Bands -= 1;
@ -334,7 +341,7 @@ vips_flatten_build( VipsObject *object )
if( black ) {
if( vips_image_generate( conversion->out,
vips_start_one, vips_flatten_black_gen, vips_stop_one,
flatten->in, flatten ) )
in, flatten ) )
return( -1 );
}
else {
@ -347,7 +354,7 @@ vips_flatten_build( VipsObject *object )
if( vips_image_generate( conversion->out,
vips_start_one, vips_flatten_gen, vips_stop_one,
flatten->in, flatten ) )
in, flatten ) )
return( -1 );
}

View File

@ -50,6 +50,7 @@
#include <math.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include "pconversion.h"
@ -142,19 +143,25 @@ vips_recomb_build( VipsObject *object )
VipsRecomb *recomb = (VipsRecomb *) object;
VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 );
VipsImage *in;
if( VIPS_OBJECT_CLASS( vips_recomb_parent_class )->build( object ) )
return( -1 );
if( vips_image_pio_input( recomb->in ) ||
vips_check_uncoded( class->nickname, recomb->in ) ||
vips_check_noncomplex( class->nickname, recomb->in ) )
in = recomb->in;
if( vips__image_decode( in, &t[0] ) )
return( -1 );
in = t[0];
if( vips_check_noncomplex( class->nickname, in ) )
return( -1 );
if( vips_image_pio_input( recomb->m ) ||
vips_check_uncoded( class->nickname, recomb->m ) ||
vips_check_noncomplex( class->nickname, recomb->m ) ||
vips_check_mono( class->nickname, recomb->m ) )
return( -1 );
if( recomb->in->Bands != recomb->m->Xsize ) {
if( in->Bands != recomb->m->Xsize ) {
vips_error( class->nickname,
"%s", _( "bands in must equal matrix width" ) );
return( -1 );
@ -165,16 +172,16 @@ vips_recomb_build( VipsObject *object )
recomb->coeff = t[0];
if( vips_image_pipelinev( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, recomb->in, NULL ) )
VIPS_DEMAND_STYLE_THINSTRIP, in, NULL ) )
return( -1 );
conversion->out->Bands = recomb->m->Ysize;
if( vips_bandfmt_isint( recomb->in->BandFmt ) )
if( vips_bandfmt_isint( in->BandFmt ) )
conversion->out->BandFmt = VIPS_FORMAT_FLOAT;
if( vips_image_generate( conversion->out,
vips_start_one, vips_recomb_gen, vips_stop_one,
recomb->in, recomb ) )
in, recomb ) )
return( -1 );
return( 0 );

View File

@ -142,7 +142,7 @@ vips_compass_class_init( VipsCompassClass *class )
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "compass";
object_class->description = _( "convolution operation" );
object_class->description = _( "convolve with rotaing mask" );
object_class->build = vips_compass_build;
VIPS_ARG_INT( class, "times", 101,

View File

@ -44,6 +44,7 @@
#include <stdio.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include "pconvolution.h"
@ -65,7 +66,10 @@ vips_conv_build( VipsObject *object )
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsConvolution *convolution = (VipsConvolution *) object;
VipsConv *conv = (VipsConv *) object;
VipsImage **t = (VipsImage **)
vips_object_local_array( object, 4 );
VipsImage *in;
INTMASK *imsk;
DOUBLEMASK *dmsk;
@ -74,6 +78,8 @@ vips_conv_build( VipsObject *object )
if( VIPS_OBJECT_CLASS( vips_conv_parent_class )->build( object ) )
return( -1 );
in = convolution->in;
/*
printf( "vips_conv_build: convolving with:\n" );
vips_matrixprint( convolution->M, NULL );
@ -86,19 +92,25 @@ vips_conv_build( VipsObject *object )
!im_local_dmask( convolution->out, dmsk ) )
return( -1 );
/* Unpack for processing.
*/
if( vips__image_decode( in, &t[0] ) )
return( -1 );
in = t[0];
switch( conv->precision ) {
case VIPS_PRECISION_INTEGER:
if( im_conv( convolution->in, convolution->out, imsk ) )
if( im_conv( in, convolution->out, imsk ) )
return( -1 );
break;
case VIPS_PRECISION_FLOAT:
if( im_conv_f( convolution->in, convolution->out, dmsk ) )
if( im_conv_f( in, convolution->out, dmsk ) )
return( -1 );
break;
case VIPS_PRECISION_APPROXIMATE:
if( im_aconv( convolution->in, convolution->out, dmsk,
if( im_aconv( in, convolution->out, dmsk,
conv->layers, conv->cluster ) )
return( -1 );
break;

View File

@ -100,7 +100,7 @@ vips_convsep_class_init( VipsConvsepClass *class )
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "convsep";
object_class->description = _( "convolution operation" );
object_class->description = _( "seperable convolution operation" );
object_class->build = vips_convsep_build;
VIPS_ARG_ENUM( class, "precision", 203,

View File

@ -108,7 +108,7 @@ vips_gaussblur_class_init( VipsGaussblurClass *class )
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "gaussblur";
object_class->description = _( "Unsharp masking for print" );
object_class->description = _( "gaussian blur" );
object_class->build = vips_gaussblur_build;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;

View File

@ -309,7 +309,7 @@ vips_sharpen_class_init( VipsSharpenClass *class )
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "sharpen";
object_class->description = _( "Unsharp masking for print" );
object_class->description = _( "unsharp masking for print" );
object_class->build = vips_sharpen_build;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;

View File

@ -98,7 +98,9 @@ static const char *openslide_suffs[] = {
".vms", ".vmu", ".ndpi", /* Hamamatsu */
".scn", /* Leica */
".mrxs", /* MIRAX */
".svslide", /* Sakura */
".tif", /* Trestle */
".bif", /* Ventana */
NULL
};

View File

@ -183,8 +183,7 @@ vips_wrap7_vargv_dispose( im_function *fn, im_object *vargv )
case VIPS_WRAP7_INTERPOLATE:
case VIPS_WRAP7_IMAGE:
if( vargv[i] )
VIPS_UNREF( vargv[i] );
VIPS_UNREF( vargv[i] );
break;
case VIPS_WRAP7_IMAGEVEC:
@ -193,13 +192,21 @@ vips_wrap7_vargv_dispose( im_function *fn, im_object *vargv )
int j;
for( j = 0; j < iv->n; j++ )
if( iv->vec[j] )
VIPS_UNREF( iv->vec[j] );
VIPS_UNREF( iv->vec[j] );
}
break;
case VIPS_WRAP7_GVALUE:
g_value_unset( vargv[i] );
if( vargv[i] ) {
GValue *value = (GValue *) vargv[i];
if( G_VALUE_TYPE( value ) )
g_value_unset( value );
}
break;
case VIPS_WRAP7_STRING:
VIPS_FREE( vargv[i] );
break;
default:
@ -686,6 +693,7 @@ vips_wrap7_class_init( VipsWrap7Class *class )
{
GObjectClass *gobject_class = (GObjectClass *) class;
VipsObjectClass *vobject_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = (VipsOperationClass *) class;
gobject_class->dispose = vips_wrap7_dispose;
gobject_class->finalize = vips_wrap7_finalize;
@ -695,6 +703,8 @@ vips_wrap7_class_init( VipsWrap7Class *class )
vobject_class->build = vips_wrap7_build;
vobject_class->summary_class = vips_wrap7_summary_class;
vobject_class->dump = vips_wrap7_dump;
operation_class->flags = VIPS_OPERATION_DEPRECATED;
}
static void

View File

@ -2357,18 +2357,17 @@ vips_openexrload( const char *filename, VipsImage **out, ... )
*
* Optional arguments:
*
* @layer: load this layer
* @level: load this level
* @associated: load this associated image
*
* Read a virtual slide supported by the OpenSlide library into a VIPS image.
* OpenSlide supports images in Aperio, Hamamatsu VMS, Hamamatsu VMU, MIRAX,
* and Trestle formats.
* OpenSlide supports images in Aperio, Hamamatsu, MIRAX, Sakura, Trestle,
* and Ventana formats.
*
* To facilitate zooming, virtual slide formats include multiple scaled-down
* versions of the high-resolution image. These are typically called
* "levels", though OpenSlide and im_openslide2vips() call them "layers".
* By default, vips_openslideload() reads the highest-resolution layer
* (layer 0). Set @layer to the layer number you want.
* "levels". By default, vips_openslideload() reads the highest-resolution
* level (level 0). Set @level to the level number you want.
*
* In addition to the slide image itself, virtual slide formats sometimes
* include additional images, such as a scan of the slide's barcode.
@ -2405,6 +2404,14 @@ vips_openslideload( const char *filename, VipsImage **out, ... )
*
* Read a FITS image file into a VIPS image.
*
* This operation can read images with up to three dimensions. Any higher
* dimensions must be empty.
*
* It can read 8, 16 and 32-bit integer images, signed and unsigned, float and
* double.
*
* FITS metadata is attached with the "fits-" prefix.
*
* See also: vips_image_new_from_file().
*
* Returns: 0 on success, -1 on error.
@ -2428,7 +2435,7 @@ vips_fitsload( const char *filename, VipsImage **out, ... )
* @filename: file to write to
* @...: %NULL-terminated list of optional named arguments
*
* Write a VIPS image to a file as FITS.
* Write a VIPS image to a file in FITS format.
*
* See also: vips_image_write_file().
*

View File

@ -150,6 +150,10 @@ typedef struct _ReadJpeg {
/* Set if we need to finish the decompress.
*/
gboolean decompressing;
/* Track the y pos during a read with this.
*/
int y_pos;
} ReadJpeg;
static int
@ -222,6 +226,8 @@ readjpeg_new( VipsImage *out, int shrink, gboolean fail, gboolean readbehind )
jpeg->eman.pub.output_message = vips__new_output_message;
jpeg->eman.fp = NULL;
jpeg->y_pos = 0;
/* jpeg_create_decompress() can fail on some sanity checks. Don't
* readjpeg_free() since we don't want to jpeg_destroy_decompress().
*/
@ -888,7 +894,7 @@ read_jpeg_generate( VipsRegion *or,
printf( "read_jpeg_generate: line %d, %d rows\n",
r->top, r->height );
#endif /*DEBUG*/
VIPS_GATE_START( "read_jpeg_generate: work" );
/* We're inside a tilecache where tiles are the full image width, so
@ -907,6 +913,11 @@ read_jpeg_generate( VipsRegion *or,
*/
g_assert( r->height == VIPS_MIN( 8, or->im->Ysize - r->top ) );
/* And check that y_pos is correct. It should be, since we are inside
* a vips_sequential().
*/
g_assert( r->top == jpeg->y_pos );
/* Here for longjmp() from vips__new_error_exit().
*/
if( setjmp( jpeg->eman.jmp ) )
@ -926,6 +937,8 @@ read_jpeg_generate( VipsRegion *or,
for( x = 0; x < sz; x++ )
row_pointer[0][x] = 255 - row_pointer[0][x];
}
jpeg->y_pos += 1;
}
VIPS_GATE_STOP( "read_jpeg_generate: work" );

View File

@ -2,7 +2,7 @@
*
* Benjamin Gilbert
*
* Copyright (c) 2011-2012 Carnegie Mellon University
* Copyright (c) 2011-2014 Carnegie Mellon University
*
* 26/11/11
* - initial version
@ -39,6 +39,8 @@
* - use threaded tile cache
* 6/8/13
* - always output solid (not transparent) pixels
* 25/1/14
* - use openslide_detect_vendor() on >= 3.4.0
*/
/*
@ -105,13 +107,28 @@ typedef struct {
int
vips__openslide_isslide( const char *filename )
{
#ifdef HAVE_OPENSLIDE_3_4
const char *vendor;
int ok;
vendor = openslide_detect_vendor( filename );
/* Generic tiled tiff images can be opened by openslide as well.
* Only offer to load this file if it's not a generic tiff since
* we want vips_tiffload() to handle these.
*/
ok = ( vendor &&
strcmp( vendor, "generic-tiff" ) != 0 );
VIPS_DEBUG_MSG( "vips__openslide_isslide: %s - %d\n", filename, ok );
return( ok );
#else
openslide_t *osr;
int ok;
ok = 0;
vips_error_freeze();
osr = openslide_open( filename );
vips_error_thaw();
if( osr ) {
const char *vendor;
@ -135,6 +152,7 @@ vips__openslide_isslide( const char *filename )
VIPS_DEBUG_MSG( "vips__openslide_isslide: %s - %d\n", filename, ok );
return( ok );
#endif
}
static void

View File

@ -140,7 +140,9 @@ static const char *vips_foreign_openslide_suffs[] = {
".vms", ".vmu", ".ndpi", /* Hamamatsu */
".scn", /* Leica */
".mrxs", /* MIRAX */
".svslide", /* Sakura */
".tif", /* Trestle */
".bif", /* Ventana */
NULL
};

View File

@ -12,6 +12,9 @@
* - support sequential read
* 5/11/13
* - rewritten scanline encode and decode, now much faster
* 23/1/14
* - put the reader globals into a struct so we can have many active
* readers
*/
/*
@ -617,38 +620,57 @@ register RESOLU *rp;
#define BUFFER_SIZE (4096)
#define BUFFER_MARGIN (256)
static unsigned char buffer[BUFFER_SIZE + BUFFER_MARGIN];
static int buffer_length = 0;
static int buffer_position = 0;
static FILE *buffer_fp = NULL;
/* Read from a FILE with a rolling memory buffer ... this lets us reduce the
* number of fgetc() and gives us some very quick readahead.
*/
static void
buffer_init( FILE *fp )
typedef struct _Buffer {
unsigned char text[BUFFER_SIZE + BUFFER_MARGIN];
int length;
int position;
FILE *fp;
} Buffer;
static Buffer *
buffer_new( FILE *fp )
{
buffer_length = 0;
buffer_position = 0;
buffer_fp = fp;
Buffer *buffer = g_new0( Buffer, 1 );
buffer->length = 0;
buffer->position = 0;
buffer->fp = fp;
return( buffer );
}
static void
buffer_free( Buffer *buffer )
{
g_free( buffer );
}
/* Make sure there are at least @require bytes of readahead available.
*/
static int
buffer_need( int require )
buffer_need( Buffer *buffer, int require )
{
int remaining;
g_assert( require < BUFFER_MARGIN );
remaining = buffer_length - buffer_position;
remaining = buffer->length - buffer->position;
if( remaining < require ) {
size_t len;
memcpy( buffer, buffer + buffer_position, remaining );
buffer_position = 0;
buffer_length = remaining;
memcpy( buffer->text,
buffer->text + buffer->position, remaining );
buffer->position = 0;
buffer->length = remaining;
len = fread( buffer + buffer_length, 1, BUFFER_SIZE,
buffer_fp );
buffer_length += len;
remaining = buffer_length - buffer_position;
len = fread( buffer->text + buffer->length,
1, BUFFER_SIZE, buffer->fp );
buffer->length += len;
remaining = buffer->length - buffer->position;
if( remaining < require ) {
vips_error( "rad2vips", "%s", _( "end of file" ) );
@ -659,26 +681,26 @@ buffer_need( int require )
return( 0 );
}
#define BUFFER_FETCH (buffer[buffer_position++])
#define BUFFER_PEEK (buffer[buffer_position])
#define BUFFER_FETCH(B) ((B)->text[(B)->position++])
#define BUFFER_PEEK(B) ((B)->text[(B)->position])
/* Read a single scanlne, encoded in the old style.
*/
static int
scanline_read_old( COLR *scanline, int width )
scanline_read_old( Buffer *buffer, COLR *scanline, int width )
{
int rshift;
rshift = 0;
while( width > 0 ) {
if( buffer_need( 4 ) )
if( buffer_need( buffer, 4 ) )
return( -1 );
scanline[0][RED] = BUFFER_FETCH;
scanline[0][GRN] = BUFFER_FETCH;
scanline[0][BLU] = BUFFER_FETCH;
scanline[0][EXP] = BUFFER_FETCH;
scanline[0][RED] = BUFFER_FETCH( buffer );
scanline[0][GRN] = BUFFER_FETCH( buffer );
scanline[0][BLU] = BUFFER_FETCH( buffer );
scanline[0][EXP] = BUFFER_FETCH( buffer );
if( scanline[0][RED] == 1 &&
scanline[0][GRN] == 1 &&
@ -706,7 +728,7 @@ scanline_read_old( COLR *scanline, int width )
/* Read a single encoded scanline.
*/
static int
scanline_read( COLR *scanline, int width )
scanline_read( Buffer *buffer, COLR *scanline, int width )
{
int i, j;
@ -714,21 +736,21 @@ scanline_read( COLR *scanline, int width )
*/
if( width < MINELEN ||
width > MAXELEN )
return( scanline_read_old( scanline, width ) );
return( scanline_read_old( buffer, scanline, width ) );
if( buffer_need( 4 ) )
if( buffer_need( buffer, 4 ) )
return( -1 );
if( BUFFER_PEEK != 2 )
return( scanline_read_old( scanline, width ) );
if( BUFFER_PEEK( buffer ) != 2 )
return( scanline_read_old( buffer, scanline, width ) );
scanline[0][RED] = BUFFER_FETCH;
scanline[0][GRN] = BUFFER_FETCH;
scanline[0][BLU] = BUFFER_FETCH;
scanline[0][EXP] = BUFFER_FETCH;
scanline[0][RED] = BUFFER_FETCH( buffer );
scanline[0][GRN] = BUFFER_FETCH( buffer );
scanline[0][BLU] = BUFFER_FETCH( buffer );
scanline[0][EXP] = BUFFER_FETCH( buffer );
if( scanline[0][GRN] != 2 ||
scanline[0][BLU] & 128 )
return( scanline_read_old( scanline + 1, width - 1 ) );
return( scanline_read_old( buffer, scanline + 1, width - 1 ) );
if( ((scanline[0][BLU] << 8) | scanline[0][EXP]) != width ) {
vips_error( "rad2vips", "%s", _( "scanline length mismatch" ) );
@ -740,10 +762,10 @@ scanline_read( COLR *scanline, int width )
int code, len;
gboolean run;
if( buffer_need( 2 ) )
if( buffer_need( buffer, 2 ) )
return( -1 );
code = BUFFER_FETCH;
code = BUFFER_FETCH( buffer );
run = code > 128;
len = run ? code & 127 : code;
@ -755,15 +777,16 @@ scanline_read( COLR *scanline, int width )
if( run ) {
int val;
val = BUFFER_FETCH;
val = BUFFER_FETCH( buffer );
while( len-- )
scanline[j++][i] = val;
}
else {
if( buffer_need( len ) )
if( buffer_need( buffer, len ) )
return( -1 );
while( len-- )
scanline[j++][i] = BUFFER_FETCH;
scanline[j++][i] =
BUFFER_FETCH( buffer );
}
}
@ -861,6 +884,7 @@ typedef struct {
double aspect;
RGBPRIMS prims;
RESOLU rs;
Buffer *buffer;
} Read;
int
@ -888,7 +912,7 @@ read_destroy( VipsObject *object, Read *read )
{
VIPS_FREE( read->filename );
VIPS_FREEF( fclose, read->fin );
buffer_init( NULL );
VIPS_FREEF( buffer_free, read->buffer );
}
static Read *
@ -920,9 +944,9 @@ read_new( const char *filename, VipsImage *out )
g_signal_connect( out, "close",
G_CALLBACK( read_destroy ), read );
if( !(read->fin = vips__file_open_read( filename, NULL, FALSE )) )
if( !(read->fin = vips__file_open_read( filename, NULL, FALSE )) ||
!(read->buffer = buffer_new( read->fin )) )
return( NULL );
buffer_init( read->fin );
return( read );
}
@ -1037,24 +1061,30 @@ rad2vips_generate( VipsRegion *or,
void *seq, void *a, void *b, gboolean *stop )
{
VipsRect *r = &or->valid;
Read *read = (Read *) a;
int y;
#ifdef DEBUG
printf( "rad2vips_get_data\n" );
printf( "rad2vips_generate: line %d, %d rows\n",
r->top, r->height );
#endif /*DEBUG*/
VIPS_GATE_START( "rad2vips_generate: work" );
for( y = 0; y < r->height; y++ ) {
COLR *buf = (COLR *)
VIPS_REGION_ADDR( or, 0, r->top + y );
if( scanline_read( buf, or->im->Xsize ) ) {
if( scanline_read( read->buffer, buf, or->im->Xsize ) ) {
vips_error( "rad2vips",
_( "read error line %d" ), r->top + y );
return( -1 );
}
}
VIPS_GATE_STOP( "rad2vips_generate: work" );
return( 0 );
}

View File

@ -47,7 +47,8 @@ int vips__tiff_write( VipsImage *in, const char *filename,
gboolean pyramid,
gboolean squash,
VipsForeignTiffResunit resunit, double xres, double yres,
gboolean bigtiff );
gboolean bigtiff,
gboolean rgbjpeg );
int vips__tiff_read( const char *filename, VipsImage *out, int page,
gboolean readbehind );

View File

@ -4,6 +4,8 @@
* - wrap a class around the tiff writer
* 17/3/12
* - argh xres/yres macro was wrong
* 26/1/14
* - add rgbjpeg flag
*/
/*
@ -75,6 +77,7 @@ typedef struct _VipsForeignSaveTiff {
double xres;
double yres;
gboolean bigtiff;
gboolean rgbjpeg;
} VipsForeignSaveTiff;
typedef VipsForeignSaveClass VipsForeignSaveTiffClass;
@ -123,7 +126,8 @@ vips_foreign_save_tiff_build( VipsObject *object )
tiff->pyramid,
tiff->squash,
tiff->resunit, tiff->xres, tiff->yres,
tiff->bigtiff ) )
tiff->bigtiff,
tiff->rgbjpeg ) )
return( -1 );
return( 0 );
@ -249,6 +253,13 @@ vips_foreign_save_tiff_class_init( VipsForeignSaveTiffClass *class )
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveTiff, bigtiff ),
FALSE );
VIPS_ARG_BOOL( class, "rgbjpeg", 20,
_( "RGB JPEG" ),
_( "Output RGB JPEG rather than YCbCr" ),
VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED,
G_STRUCT_OFFSET( VipsForeignSaveTiff, rgbjpeg ),
FALSE );
}
static void

View File

@ -136,6 +136,8 @@
* 24/9/13
* - support many more vips formats, eg. complex, 32-bit int, any number
* of bands, etc., see the tiff loader
* 26/1/14
* - add RGB as well as YCbCr write
*/
/*
@ -261,6 +263,7 @@ typedef struct tiff_write {
float yres; /* Resolution in Y */
char *icc_profile; /* Profile to embed */
int bigtiff; /* True for bigtiff write */
int rgbjpeg; /* True for RGB not YCbCr */
GMutex *write_lock; /* Lock TIFF*() calls with this */
} TiffWrite;
@ -529,7 +532,8 @@ write_tiff_header( TiffWrite *tw, TIFF *tif, int width, int height )
}
else if( tw->compression == COMPRESSION_JPEG &&
tw->im->Bands == 3 &&
tw->im->BandFmt == VIPS_FORMAT_UCHAR ) {
tw->im->BandFmt == VIPS_FORMAT_UCHAR &&
!tw->rgbjpeg ) {
/* This signals to libjpeg that it can do
* YCbCr chrominance subsampling from RGB, not
* that we will supply the image as YCbCr.
@ -1291,7 +1295,8 @@ make_tiff_write( VipsImage *im, const char *filename,
gboolean pyramid,
gboolean squash,
VipsForeignTiffResunit resunit, double xres, double yres,
gboolean bigtiff )
gboolean bigtiff,
gboolean rgbjpeg )
{
TiffWrite *tw;
@ -1313,6 +1318,7 @@ make_tiff_write( VipsImage *im, const char *filename,
tw->onebit = squash;
tw->icc_profile = profile;
tw->bigtiff = bigtiff;
tw->rgbjpeg = rgbjpeg;
tw->write_lock = NULL;
tw->resunit = get_resunit( resunit );
@ -1531,7 +1537,8 @@ vips__tiff_write( VipsImage *in, const char *filename,
gboolean pyramid,
gboolean squash,
VipsForeignTiffResunit resunit, double xres, double yres,
gboolean bigtiff )
gboolean bigtiff,
gboolean rgbjpeg )
{
TiffWrite *tw;
int res;
@ -1553,7 +1560,7 @@ vips__tiff_write( VipsImage *in, const char *filename,
if( !(tw = make_tiff_write( in, filename,
compression, Q, predictor, profile,
tile, tile_width, tile_height, pyramid, squash,
resunit, xres, yres, bigtiff )) )
resunit, xres, yres, bigtiff, rgbjpeg )) )
return( -1 );
if( tw->pyramid ) {
if( !(tw->bname = vips__temp_name( "%s.tif" )) ||

View File

@ -75,6 +75,7 @@
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include "pfreqfilt.h"
#ifdef HAVE_FFTW
@ -294,22 +295,30 @@ vips_fwfft_build( VipsObject *object )
VipsFwfft *fwfft = (VipsFwfft *) object;
VipsImage **t = (VipsImage **) vips_object_local_array( object, 4 );
VipsImage *in;
if( VIPS_OBJECT_CLASS( vips_fwfft_parent_class )->
build( object ) )
return( -1 );
if( vips_bandfmt_iscomplex( freqfilt->in->BandFmt ) ) {
if( vips__fftproc( VIPS_OBJECT( fwfft ), freqfilt->in, &t[0],
in = freqfilt->in;
if( vips__image_decode( in, &t[0] ) )
return( -1 );
in = t[0];
if( vips_bandfmt_iscomplex( in->BandFmt ) ) {
if( vips__fftproc( VIPS_OBJECT( fwfft ), in, &t[1],
cfwfft1 ) )
return( -1 );
}
else {
if( vips__fftproc( VIPS_OBJECT( fwfft ), freqfilt->in, &t[0],
if( vips__fftproc( VIPS_OBJECT( fwfft ), in, &t[1],
rfwfft1 ) )
return( -1 );
}
if( vips_image_write( t[0], freqfilt->out ) )
if( vips_image_write( t[1], freqfilt->out ) )
return( -1 );
return( 0 );

View File

@ -64,6 +64,7 @@
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include "pfreqfilt.h"
#ifdef HAVE_FFTW
@ -207,22 +208,30 @@ vips_invfft_build( VipsObject *object )
VipsInvfft *invfft = (VipsInvfft *) object;
VipsImage **t = (VipsImage **) vips_object_local_array( object, 4 );
VipsImage *in;
if( VIPS_OBJECT_CLASS( vips_invfft_parent_class )->
build( object ) )
return( -1 );
in = freqfilt->in;
if( vips__image_decode( in, &t[0] ) )
return( -1 );
in = t[0];
if( invfft->real ) {
if( vips__fftproc( VIPS_OBJECT( invfft ),
freqfilt->in, &t[0], rinvfft1 ) )
in, &t[1], rinvfft1 ) )
return( -1 );
}
else {
if( vips__fftproc( VIPS_OBJECT( invfft ),
freqfilt->in, &t[0], cinvfft1 ) )
in, &t[1], cinvfft1 ) )
return( -1 );
}
if( vips_image_write( t[0], freqfilt->out ) )
if( vips_image_write( t[1], freqfilt->out ) )
return( -1 );
return( 0 );

View File

@ -60,6 +60,7 @@
#include <string.h>
#include <vips/vips.h>
#include <vips/internal.h>
typedef struct _VipsHistLocal {
VipsOperation parent_instance;
@ -235,8 +236,11 @@ vips_hist_local_build( VipsObject *object )
in = local->in;
if( vips_check_uncoded( class->nickname, in ) ||
vips_check_format( class->nickname, in, VIPS_FORMAT_UCHAR ) )
if( vips__image_decode( in, &t[0] ) )
return( -1 );
in = t[0];
if( vips_check_format( class->nickname, in, VIPS_FORMAT_UCHAR ) )
return( -1 );
if( local->width > in->Xsize ||
@ -247,13 +251,13 @@ vips_hist_local_build( VipsObject *object )
/* Expand the input.
*/
if( vips_embed( in, &t[0],
if( vips_embed( in, &t[1],
local->width / 2, local->height / 2,
in->Xsize + local->width - 1, in->Ysize + local->height - 1,
"extend", VIPS_EXTEND_COPY,
NULL ) )
return( -1 );
in = t[0];
in = t[1];
g_object_set( object, "out", vips_image_new(), NULL );

View File

@ -111,6 +111,7 @@ vips_histogram_build( VipsObject *object )
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsHistogramClass *hclass = VIPS_HISTOGRAM_GET_CLASS( histogram );
VipsImage **decode;
VipsImage **format;
VipsImage **band;
VipsImage **size;
@ -134,6 +135,7 @@ vips_histogram_build( VipsObject *object )
*/
g_assert( !histogram->in[histogram->n] );
decode = (VipsImage **) vips_object_local_array( object, histogram->n );
format = (VipsImage **) vips_object_local_array( object, histogram->n );
band = (VipsImage **) vips_object_local_array( object, histogram->n );
size = (VipsImage **) vips_object_local_array( object, histogram->n );
@ -141,8 +143,8 @@ vips_histogram_build( VipsObject *object )
g_object_set( histogram, "out", vips_image_new(), NULL );
for( i = 0; i < histogram->n; i++ )
if( vips_check_uncoded( class->nickname, histogram->in[i] ) ||
vips_check_hist( class->nickname, histogram->in[i] ) )
if( vips__image_decode( histogram->in[i], &decode[i] ) ||
vips_check_hist( class->nickname, decode[i] ) )
return( -1 );
/* Cast our input images up to a common format, bands and size. If
@ -150,13 +152,12 @@ vips_histogram_build( VipsObject *object )
*/
if( hclass->input_format != VIPS_FORMAT_NOTSET ) {
for( i = 0; i < histogram->n; i++ )
if( vips_cast( histogram->in[i], &format[i],
if( vips_cast( decode[i], &format[i],
hclass->input_format, NULL ) )
return( -1 );
}
else {
if( vips__formatalike_vec( histogram->in,
format, histogram->n ) )
if( vips__formatalike_vec( decode, format, histogram->n ) )
return( -1 );
}

View File

@ -64,6 +64,7 @@
#include <math.h>
#include <vips/vips.h>
#include <vips/internal.h>
typedef struct _VipsStdif {
VipsOperation parent_instance;
@ -223,8 +224,11 @@ vips_stdif_build( VipsObject *object )
in = stdif->in;
if( vips_check_uncoded( class->nickname, in ) ||
vips_check_format( class->nickname, in, VIPS_FORMAT_UCHAR ) )
if( vips__image_decode( in, &t[0] ) )
return( -1 );
in = t[0];
if( vips_check_format( class->nickname, in, VIPS_FORMAT_UCHAR ) )
return( -1 );
if( stdif->width > in->Xsize ||
@ -239,13 +243,13 @@ vips_stdif_build( VipsObject *object )
/* Expand the input.
*/
if( vips_embed( in, &t[0],
if( vips_embed( in, &t[1],
stdif->width / 2, stdif->height / 2,
in->Xsize + stdif->width - 1, in->Ysize + stdif->height - 1,
"extend", VIPS_EXTEND_COPY,
NULL ) )
return( -1 );
in = t[0];
in = t[1];
g_object_set( object, "out", vips_image_new(), NULL );

View File

@ -298,6 +298,8 @@ IMAGE *vips__deprecated_open_write( const char *filename );
int vips__input_interpolate_init( im_object *obj, char *str );
int vips__image_decode( VipsImage *in, VipsImage **out );
#ifdef __cplusplus
}
#endif /*__cplusplus*/

View File

@ -55,34 +55,6 @@ typedef struct _VipsObjectClass VipsObjectClass;
/* Track extra stuff for arguments to objects
*/
/**
* VipsArgumentFlags:
* @VIPS_ARGUMENT_NONE: no flags
* @VIPS_ARGUMENT_REQUIRED: must be set in the constructor
* @VIPS_ARGUMENT_CONSTRUCT: can only be set in the constructor
* @VIPS_ARGUMENT_SET_ONCE: can only be set once
* @VIPS_ARGUMENT_SET_ALWAYS: don't do use-before-set checks
* @VIPS_ARGUMENT_INPUT: is an input argument (one we depend on)
* @VIPS_ARGUMENT_OUTPUT: is an output argument (depends on us)
* @VIPS_ARGUMENT_DEPRECATED: just there for back-compat, hide
*
* Flags we associate with each object argument.
*
* Have separate input & output flags. Both set is an error; neither set is OK.
*
* Input gobjects are automatically reffed, output gobjects automatically ref
* us. We also automatically watch for "destroy" and unlink.
*
* @VIPS_ARGUMENT_SET_ALWAYS is handy for arguments which are set from C. For
* example, VipsImage::width is a property that gives access to the Xsize
* member of struct _VipsImage. We default its 'assigned' to TRUE
* since the field is always set directly by C.
*
* @VIPS_ARGUMENT_DEPRECATED arguments are not shown in help text, are not
* looked for if required, are not checked for "have-been-set". You can
* deprecate a required argument, but you must obviously add a new required
* argument if you do.
*/
typedef enum /*< flags >*/ {
VIPS_ARGUMENT_NONE = 0,
VIPS_ARGUMENT_REQUIRED = 1,
@ -461,6 +433,7 @@ struct _VipsObject {
* profiling.
*/
size_t local_memory;
};
struct _VipsObjectClass {
@ -561,6 +534,13 @@ struct _VipsObjectClass {
*/
GSList *argument_table_traverse;
GType argument_table_traverse_gtype;
/* Reserved for future expansion.
*/
void (*_vips_reserved1)( void );
void (*_vips_reserved2)( void );
void (*_vips_reserved3)( void );
void (*_vips_reserved4)( void );
};
gboolean vips_value_is_null( GParamSpec *psoec, const GValue *value );

View File

@ -41,7 +41,8 @@ typedef enum /*< flags >*/ {
VIPS_OPERATION_NONE = 0,
VIPS_OPERATION_SEQUENTIAL = 1,
VIPS_OPERATION_SEQUENTIAL_UNBUFFERED = 2,
VIPS_OPERATION_NOCACHE = 4
VIPS_OPERATION_NOCACHE = 4,
VIPS_OPERATION_DEPRECATED = 8
} VipsOperationFlags;
#define VIPS_TYPE_OPERATION (vips_operation_get_type())

View File

@ -89,8 +89,8 @@ typedef struct {
GThread *thread; /* Just for sanity checking */
} VipsBufferThread;
/* Per-image buffer cache. Hash to this from VipsBufferCache.
* We can't store the GSList directly in the hash table, as GHashTable lacks an
/* Per-image buffer cache. Hash to this from VipsBufferThread::hash.
* We can't store the GSList directly in the hash table as GHashTable lacks an
* update operation and we'd need to _remove() and _insert() on every list
* operation.
*/
@ -127,6 +127,8 @@ VipsBuffer *vips_buffer_unref_ref( VipsBuffer *buffer,
struct _VipsImage *im, VipsRect *area );
void vips_buffer_print( VipsBuffer *buffer );
void vips__render_shutdown( void );
/* Sections of region.h that are private to VIPS.
*/

View File

@ -120,6 +120,8 @@ int vips_region_prepare_to( VipsRegion *reg,
VipsRegion *dest, VipsRect *r, int x, int y );
int vips_region_prepare_many( VipsRegion **reg, VipsRect *r );
void vips_region_invalidate( VipsRegion *reg );
void vips_region_dump_all( void );
/* Macros on VipsRegion.

View File

@ -50,10 +50,10 @@
*/
/*
#define DEBUG_CREATE
#define DEBUG_VERBOSE
#define DEBUG
#define DEBUG_CREATE
*/
#define DEBUG
#ifdef HAVE_CONFIG_H
#include <config.h>
@ -70,11 +70,11 @@
#ifdef DEBUG
/* Track all regions here for debugging.
*/
static GSList *vips__buffers_all = NULL;
static GSList *vips__buffer_all = NULL;
#endif /*DEBUG*/
#ifdef DEBUG_CREATE
static int buffer_cache_n = 0;
static GSList *vips__buffer_cache_all = NULL;
#endif /*DEBUG_CREATE*/
/* The maximum numbers of buffers we hold in reserve per image.
@ -87,13 +87,19 @@ static GPrivate *buffer_thread_key = NULL;
static void *
vips_buffer_dump( VipsBuffer *buffer, size_t *reserve, size_t *alive )
{
vips_buffer_print( buffer );
if( buffer->im &&
buffer->buf ) {
printf( "buffer %p, %gMB\n",
buffer->buf &&
buffer->cache ) {
printf( "buffer %p, %.3g MB\n",
buffer, buffer->bsize / (1024 * 1024.0) );
*alive += buffer->bsize;
}
else if( !buffer->im )
else
if( buffer->im &&
buffer->buf &&
!buffer->cache )
*reserve += buffer->bsize;
else
printf( "buffer craziness!\n" );
@ -101,18 +107,47 @@ vips_buffer_dump( VipsBuffer *buffer, size_t *reserve, size_t *alive )
return( NULL );
}
#ifdef DEBUG_CREATE
static void *
vips_buffer_cache_dump( VipsBufferCache *cache )
{
printf( "VipsBufferCache: %p\n", cache );
printf( "\t%d buffers\n", g_slist_length( cache->buffers ) );
printf( "\tthread %p\n", cache->thread );
printf( "\timage %p\n", cache->im );
printf( "\tbuffer_thread %p\n", cache->buffer_thread );
printf( "\t%d in reserve\n", g_slist_length( cache->reserve ) );
return( NULL );
}
#endif /*DEBUG_CREATE*/
void
vips_buffer_dump_all( void )
{
size_t reserve;
size_t alive;
if( vips__buffer_all ) {
size_t reserve;
size_t alive;
reserve = 0;
alive = 0;
vips_slist_map2( vips__buffers_all,
(VipsSListMap2Fn) vips_buffer_dump, &reserve, &alive );
printf( "%gMB alive\n", alive / (1024 * 1024.0) );
printf( "%gMB in reserve\n", reserve / (1024 * 1024.0) );
printf( "buffers:\n" );
reserve = 0;
alive = 0;
vips_slist_map2( vips__buffer_all,
(VipsSListMap2Fn) vips_buffer_dump, &reserve, &alive );
printf( "%.3g MB alive\n", alive / (1024 * 1024.0) );
printf( "%.3g MB in reserve\n", reserve / (1024 * 1024.0) );
}
#ifdef DEBUG_CREATE
if( vips__buffer_cache_all ) {
printf( "buffers: %d buffer cache still alive\n",
g_slist_length( vips__buffer_cache_all ) );
vips_slist_map2( vips__buffer_cache_all,
(VipsSListMap2Fn) vips_buffer_cache_dump, NULL, NULL );
printf( "g_thread_self() == %p\n", g_thread_self() );
}
#endif /*DEBUG_CREATE*/
}
#endif /*DEBUG*/
@ -126,8 +161,8 @@ vips_buffer_free( VipsBuffer *buffer )
#ifdef DEBUG
g_mutex_lock( vips__global_lock );
g_assert( g_slist_find( vips__buffers_all, buffer ) );
vips__buffers_all = g_slist_remove( vips__buffers_all, buffer );
g_assert( g_slist_find( vips__buffer_all, buffer ) );
vips__buffer_all = g_slist_remove( vips__buffer_all, buffer );
g_mutex_unlock( vips__global_lock );
#endif /*DEBUG*/
@ -146,11 +181,15 @@ buffer_cache_free( VipsBufferCache *cache )
GSList *p;
#ifdef DEBUG_CREATE
buffer_cache_n -= 1;
g_mutex_lock( vips__global_lock );
vips__buffer_cache_all =
g_slist_remove( vips__buffer_cache_all, cache );
g_mutex_unlock( vips__global_lock );
printf( "buffer_cache_free: freeing cache %p on thread %p\n",
cache, g_thread_self() );
printf( "\t(%d caches left)\n", buffer_cache_n );
printf( "\t(%d caches left)\n",
g_slist_length( vips__buffer_cache_all ) );
#endif /*DEBUG_CREATE*/
/* Need to mark undone so we don't try and take them off this hash on
@ -187,11 +226,15 @@ buffer_cache_new( VipsBufferThread *buffer_thread, VipsImage *im )
cache->n_reserve = 0;
#ifdef DEBUG_CREATE
buffer_cache_n += 1;
g_mutex_lock( vips__global_lock );
vips__buffer_cache_all =
g_slist_prepend( vips__buffer_cache_all, cache );
g_mutex_unlock( vips__global_lock );
printf( "buffer_cache_new: new cache %p for thread %p\n",
cache, g_thread_self() );
printf( "\t(%d caches now)\n", buffer_cache_n );
printf( "\t(%d caches now)\n",
g_slist_length( vips__buffer_cache_all ) );
#endif /*DEBUG_CREATE*/
return( cache );
@ -276,7 +319,6 @@ vips_buffer_undone( VipsBuffer *buffer )
{
if( buffer->done ) {
VipsBufferCache *cache = buffer->cache;
VipsBufferThread *buffer_thread = cache->buffer_thread;
#ifdef DEBUG_VERBOSE
printf( "vips_buffer_undone: thread %p removing "
@ -285,9 +327,9 @@ vips_buffer_undone( VipsBuffer *buffer )
#endif /*DEBUG_VERBOSE*/
g_assert( cache->thread == g_thread_self() );
g_assert( buffer_thread->thread == cache->thread );
g_assert( cache->buffer_thread->thread == cache->thread );
g_assert( g_slist_find( cache->buffers, buffer ) );
g_assert( buffer_thread == buffer_thread_get() );
g_assert( cache->buffer_thread == buffer_thread_get() );
cache->buffers = g_slist_remove( cache->buffers, buffer );
@ -404,8 +446,8 @@ vips_buffer_new( VipsImage *im, VipsRect *area )
#ifdef DEBUG
g_mutex_lock( vips__global_lock );
vips__buffers_all =
g_slist_prepend( vips__buffers_all, buffer );
vips__buffer_all =
g_slist_prepend( vips__buffer_all, buffer );
g_mutex_unlock( vips__global_lock );
#endif /*DEBUG*/
}

View File

@ -624,6 +624,7 @@ vips_operation_flags_get_type( void )
{VIPS_OPERATION_SEQUENTIAL, "VIPS_OPERATION_SEQUENTIAL", "sequential"},
{VIPS_OPERATION_SEQUENTIAL_UNBUFFERED, "VIPS_OPERATION_SEQUENTIAL_UNBUFFERED", "sequential-unbuffered"},
{VIPS_OPERATION_NOCACHE, "VIPS_OPERATION_NOCACHE", "nocache"},
{VIPS_OPERATION_DEPRECATED, "VIPS_OPERATION_DEPRECATED", "deprecated"},
{0, NULL, NULL}
};

View File

@ -937,6 +937,7 @@ vips_image_build( VipsObject *object )
image->Type = VIPS_INTERPRETATION_MULTIBAND;
image->dtype = VIPS_IMAGE_SETBUF_FOREIGN;
image->dhint = VIPS_DEMAND_STYLE_ANY;
break;
@ -952,9 +953,9 @@ vips_image_build( VipsObject *object )
}
static void *
vips_region_invalidate( VipsRegion *reg )
vips_image_real_invalidate_cb( VipsRegion *reg )
{
reg->invalid = TRUE;
vips_region_invalidate( reg );
return( NULL );
}
@ -971,7 +972,7 @@ vips_image_real_invalidate( VipsImage *image )
VIPS_GATE_STOP( "vips_image_real_invalidate: wait" );
(void) vips_slist_map2( image->regions,
(VipsSListMap2Fn) vips_region_invalidate, NULL, NULL );
(VipsSListMap2Fn) vips_image_real_invalidate_cb, NULL, NULL );
g_mutex_unlock( image->sslock );
}
@ -1273,6 +1274,8 @@ vips_image_invalidate_all_cb( VipsImage *image )
* is, images which depend on this image.
*
* The "invalidate" callback is triggered for all invalidated images.
*
* See also: vips_region_invalidate().
*/
void
vips_image_invalidate_all( VipsImage *image )

View File

@ -369,6 +369,10 @@ vips_leak( void )
fprintf( stderr, "%s", vips_buf_all( &buf ) );
vips__type_leak();
#ifdef DEBUG
#endif /*DEBUG*/
vips_buffer_dump_all();
}
/**
@ -419,6 +423,8 @@ vips_shutdown( void )
vips__thread_gate_stop( "init: main" );
}
vips__render_shutdown();
vips_thread_shutdown();
vips__thread_profile_stop();

View File

@ -79,6 +79,35 @@
*
*/
/**
* VipsArgumentFlags:
* @VIPS_ARGUMENT_NONE: no flags
* @VIPS_ARGUMENT_REQUIRED: must be set in the constructor
* @VIPS_ARGUMENT_CONSTRUCT: can only be set in the constructor
* @VIPS_ARGUMENT_SET_ONCE: can only be set once
* @VIPS_ARGUMENT_SET_ALWAYS: don't do use-before-set checks
* @VIPS_ARGUMENT_INPUT: is an input argument (one we depend on)
* @VIPS_ARGUMENT_OUTPUT: is an output argument (depends on us)
* @VIPS_ARGUMENT_DEPRECATED: just there for back-compat, hide
*
* Flags we associate with each object argument.
*
* Have separate input & output flags. Both set is an error; neither set is OK.
*
* Input gobjects are automatically reffed, output gobjects automatically ref
* us. We also automatically watch for "destroy" and unlink.
*
* @VIPS_ARGUMENT_SET_ALWAYS is handy for arguments which are set from C. For
* example, VipsImage::width is a property that gives access to the Xsize
* member of struct _VipsImage. We default its 'assigned' to TRUE
* since the field is always set directly by C.
*
* @VIPS_ARGUMENT_DEPRECATED arguments are not shown in help text, are not
* looked for if required, are not checked for "have-been-set". You can
* deprecate a required argument, but you must obviously add a new required
* argument if you do.
*/
/* Our signals.
*/
enum {
@ -1708,9 +1737,9 @@ gboolean
vips_object_argument_needsstring( VipsObject *object, const char *name )
{
GParamSpec *pspec;
GType otype;
VipsArgumentClass *argument_class;
VipsArgumentInstance *argument_instance;
GType otype;
VipsObjectClass *oclass;
#ifdef DEBUG
@ -1725,10 +1754,15 @@ vips_object_argument_needsstring( VipsObject *object, const char *name )
/* Bools, input or output, don't need args.
*/
return( FALSE );
else if( argument_class->flags & VIPS_ARGUMENT_INPUT )
if( argument_class->flags & VIPS_ARGUMENT_INPUT )
/* All other inputs need something.
*/
return( TRUE );
/* Just output objects.
*/
if( (otype = G_PARAM_SPEC_VALUE_TYPE( pspec )) &&
g_type_is_a( otype, VIPS_TYPE_OBJECT ) &&
(oclass = g_type_class_ref( otype )) )

View File

@ -70,6 +70,7 @@
* @VIPS_OPERATION_NONE: no flags
* @VIPS_OPERATION_SEQUENTIAL: can work sequentially
* @VIPS_OPERATION_NOCACHE: must not be cached
* @VIPS_OPERATION_DEPRECATED: a compatibility thing
*
* Flags we associate with an operation.
*
@ -83,6 +84,9 @@
*
* @VIPS_OPERATION_NOCACHE means that the operation must not be cached by
* vips.
*
* @VIPS_OPERATION_DEPRECATED means this is an old operation kept in vips for
* compatibility only and should be hidden from users.
*/
/* Abstract base class for operations.

View File

@ -1375,6 +1375,25 @@ vips_region_prepare_many( VipsRegion **reg, VipsRect *r )
return( 0 );
}
/**
* vips_region_invalidate:
* @reg: region to invalidate
*
* Mark a region as containing invalid pixels. Calling this function means
* that the next time vips_region_prepare() is called, the region will be
* recalculated.
*
* This is faster than calling vips_image_invalidate_all(), but obviously only
* affects a single region.
*
* See also: vips_image_invalidate_all(), vips_region_prepare().
*/
void
vips_region_invalidate( VipsRegion *reg )
{
reg->invalid = TRUE;
}
#ifdef VIPS_DEBUG
static void *
vips_region_dump_all_cb( VipsRegion *region, size_t *alive )

View File

@ -5,6 +5,8 @@
* 25/11/10
* - in synchronous mode, use a single region for input and save huge
* mem use
* 20/1/14
* - bg render thread quits on shutdown
*/
/*
@ -160,6 +162,10 @@ static GThread *render_thread = NULL;
*/
static VipsSemaphore render_dirty_sem;
/* Set this to ask the render thread to quit.
*/
static gboolean render_kill = FALSE;
/* All the renders with dirty tiles.
*/
static GMutex *render_dirty_lock = NULL;
@ -424,6 +430,13 @@ render_work( VipsThreadState *state, void *a )
}
tile->painted = TRUE;
/* All downstream images must drop caches, since we've (effectively)
* modified render->out.
*/
vips_image_invalidate_all( render->out );
if( render->mask )
vips_image_invalidate_all( render->mask );
/* Now clients can update.
*/
if( render->notify )
@ -471,44 +484,67 @@ render_dirty_put( Render *render )
static void *
render_thread_main( void *client )
{
for(;;) {
Render *render;
Render *render;
if( (render = render_dirty_get()) ) {
/* Ignore errors, I'm not sure what we'd do with them
* anyway.
*/
VIPS_DEBUG_MSG_GREEN( "render_thread_main: "
"threadpool start\n" );
while( (render = render_dirty_get()) &&
!render_kill ) {
VIPS_DEBUG_MSG_GREEN( "render_thread_main: "
"threadpool start\n" );
render_reschedule = FALSE;
if( vips_threadpool_run( render->in,
render_thread_state_new,
render_allocate,
render_work,
NULL,
render ) )
VIPS_DEBUG_MSG_RED( "render_thread_main: "
"threadpool_run failed\n" );
render_reschedule = FALSE;
if( vips_threadpool_run( render->in,
render_thread_state_new,
render_allocate,
render_work,
NULL,
render ) )
VIPS_DEBUG_MSG_RED( "render_thread_main: "
"threadpool_run failed\n" );
VIPS_DEBUG_MSG_GREEN( "render_thread_main: "
"threadpool return\n" );
VIPS_DEBUG_MSG_GREEN( "render_thread_main: "
"threadpool return\n" );
/* Add back to the jobs list, if we need to.
*/
render_dirty_put( render );
/* Add back to the jobs list, if we need to.
*/
render_dirty_put( render );
/* _get() does a ref to make sure we keep the render
* alive during processing ... unref before we loop.
* This can kill off the render.
*/
render_unref( render );
}
/* _get() does a ref to make sure we keep the render
* alive during processing ... unref before we loop.
* This can kill off the render.
*/
render_unref( render );
}
return( NULL );
}
void
vips__render_shutdown( void )
{
/* We may come here without having inited.
*/
if( !render_dirty_lock )
return;
g_mutex_lock( render_dirty_lock );
if( render_thread ) {
GThread *thread;
thread = render_thread;
render_thread = NULL;
g_mutex_unlock( render_dirty_lock );
render_reschedule = TRUE;
render_kill = TRUE;
vips_semaphore_up( &render_dirty_sem );
(void) g_thread_join( thread );
}
else
g_mutex_unlock( render_dirty_lock );
}
/* Create our set of RenderThread. Assume we're single-threaded here.
*/
static int
@ -896,14 +932,17 @@ static int
image_fill( VipsRegion *out, void *seq, void *a, void *b, gboolean *stop )
{
Render *render = (Render *) a;
int tile_width = render->tile_width;
int tile_height = render->tile_height;
VipsRegion *reg = (VipsRegion *) seq;
VipsRect *r = &out->valid;
int x, y;
/* Find top left of tiles we need.
*/
int xs = (r->left / render->tile_width) * render->tile_width;
int ys = (r->top / render->tile_height) * render->tile_height;
int xs = (r->left / tile_width) * tile_width;
int ys = (r->top / tile_height) * tile_height;
VIPS_DEBUG_MSG( "image_fill: left = %d, top = %d, "
"width = %d, height = %d\n",
@ -918,15 +957,15 @@ image_fill( VipsRegion *out, void *seq, void *a, void *b, gboolean *stop )
*/
for( y = ys; y < VIPS_RECT_BOTTOM( r ); y += render->tile_height )
for( x = xs; x < VIPS_RECT_RIGHT( r ); x += render->tile_width ) {
for( y = ys; y < VIPS_RECT_BOTTOM( r ); y += tile_height )
for( x = xs; x < VIPS_RECT_RIGHT( r ); x += tile_width ) {
VipsRect area;
Tile *tile;
area.left = x;
area.top = y;
area.width = render->tile_width;
area.height = render->tile_height;
area.width = tile_width;
area.height = tile_height;
tile = render_tile_request( render, reg, &area );
if( tile )
@ -956,13 +995,16 @@ static int
mask_fill( VipsRegion *out, void *seq, void *a, void *b, gboolean *stop )
{
Render *render = (Render *) a;
int tile_width = render->tile_width;
int tile_height = render->tile_height;
VipsRect *r = &out->valid;
int x, y;
/* Find top left of tiles we need.
*/
int xs = (r->left / render->tile_width) * render->tile_width;
int ys = (r->top / render->tile_height) * render->tile_height;
int xs = (r->left / tile_width) * tile_width;
int ys = (r->top / tile_height) * tile_height;
VIPS_DEBUG_MSG( "mask_fill: left = %d, top = %d, "
"width = %d, height = %d\n",
@ -970,16 +1012,16 @@ mask_fill( VipsRegion *out, void *seq, void *a, void *b, gboolean *stop )
g_mutex_lock( render->lock );
for( y = ys; y < VIPS_RECT_BOTTOM( r ); y += render->tile_height )
for( x = xs; x < VIPS_RECT_RIGHT( r ); x += render->tile_width ) {
for( y = ys; y < VIPS_RECT_BOTTOM( r ); y += tile_height )
for( x = xs; x < VIPS_RECT_RIGHT( r ); x += tile_width ) {
VipsRect area;
Tile *tile;
int value;
area.left = x;
area.top = y;
area.width = render->tile_width;
area.height = render->tile_height;
area.width = tile_width;
area.height = tile_height;
tile = render_tile_lookup( render, &area );
value = (tile &&

View File

@ -44,6 +44,7 @@
#include <stdio.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include "pmorphology.h"
@ -83,15 +84,22 @@ vips_morph_build( VipsObject *object )
VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 );
INTMASK *imsk;
VipsImage *in;
g_object_set( morph, "out", vips_image_new(), NULL );
if( VIPS_OBJECT_CLASS( vips_morph_parent_class )->build( object ) )
return( -1 );
if( vips_check_matrix( class->nickname, morph->mask, &t[0] ) )
in = morphology->in;
if( vips__image_decode( in, &t[0] ) )
return( -1 );
in = t[0];
if( vips_check_matrix( class->nickname, morph->mask, &t[1] ) )
return( -1 );
morph->M = t[0];
morph->M = t[1];
if( !(imsk = im_vips2imask( morph->M, class->nickname )) ||
!im_local_imask( morph->out, imsk ) )
@ -99,12 +107,12 @@ vips_morph_build( VipsObject *object )
switch( morph->morph ) {
case VIPS_OPERATION_MORPHOLOGY_DILATE:
if( im_dilate( morphology->in, morph->out, imsk ) )
if( im_dilate( in, morph->out, imsk ) )
return( -1 );
break;
case VIPS_OPERATION_MORPHOLOGY_ERODE:
if( im_erode( morphology->in, morph->out, imsk ) )
if( im_erode( in, morph->out, imsk ) )
return( -1 );
break;

View File

@ -64,6 +64,7 @@
#include <math.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include "pmorphology.h"
@ -340,8 +341,11 @@ vips_rank_build( VipsObject *object )
in = morphology->in;
if( vips_check_uncoded( class->nickname, in ) ||
vips_check_noncomplex( class->nickname, in ) )
if( vips__image_decode( in, &t[0] ) )
return( -1 );
in = t[0];
if( vips_check_noncomplex( class->nickname, in ) )
return( -1 );
if( rank->width > in->Xsize ||
rank->height > in->Ysize ) {
@ -356,13 +360,13 @@ vips_rank_build( VipsObject *object )
/* Expand the input.
*/
if( vips_embed( in, &t[0],
if( vips_embed( in, &t[1],
rank->width / 2, rank->height / 2,
in->Xsize + rank->width - 1, in->Ysize + rank->height - 1,
"extend", VIPS_EXTEND_COPY,
NULL ) )
return( -1 );
in = t[0];
in = t[1];
g_object_set( object, "out", vips_image_new(), NULL );

View File

@ -79,6 +79,8 @@
* 14/12/12
* - redone as a class
* - added input space translation
* 22/1/14
* - auto RAD decode
*/
/*
@ -373,13 +375,33 @@ vips_affine_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
return( 0 );
}
/* Unpack to a format that we can compute with.
*/
int
vips__image_decode( VipsImage *in, VipsImage **out )
{
if( in->Coding == VIPS_CODING_LABQ ) {
if( vips_LabQ2LabS( in, out, NULL ) )
return( -1 );
}
else if( in->Coding == VIPS_CODING_RAD ) {
if( vips_rad2float( in, out, NULL ) )
return( -1 );
}
else {
if( vips_copy( in, out, NULL ) )
return( -1 );
}
return( 0 );
}
static int
vips_affine_build( VipsObject *object )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsResample *resample = VIPS_RESAMPLE( object );
VipsAffine *affine = (VipsAffine *) object;
VipsImage **t = (VipsImage **)
vips_object_local_array( object, 4 );
@ -392,7 +414,7 @@ vips_affine_build( VipsObject *object )
if( VIPS_OBJECT_CLASS( vips_affine_parent_class )->build( object ) )
return( -1 );
if( vips_check_coding_noneorlabq( class->nickname, resample->in ) )
if( vips_check_coding_known( class->nickname, resample->in ) )
return( -1 );
if( vips_check_vector_length( class->nickname,
affine->matrix->n, 4 ) )
@ -463,23 +485,19 @@ vips_affine_build( VipsObject *object )
return( -1 );
}
/* Unpack labq for processing.
*/
if( in->Coding == VIPS_CODING_LABQ ) {
if( vips_LabQ2LabS( in, &t[0], NULL ) )
return( -1 );
in = t[0];
}
if( vips__image_decode( in, &t[0] ) )
return( -1 );
in = t[0];
/* Add new pixels around the input so we can interpolate at the edges.
*/
if( vips_embed( in, &t[1],
if( vips_embed( in, &t[2],
window_offset, window_offset,
in->Xsize + window_size, in->Ysize + window_size,
"extend", VIPS_EXTEND_COPY,
NULL ) )
return( -1 );
in = t[1];
in = t[2];
/* Normally SMALLTILE ... except if this is a size up/down affine.
*/

View File

@ -428,7 +428,7 @@ vips_interpolate_bicubic_class_init( VipsInterpolateBicubicClass *iclass )
VIPS_INTERPOLATE_CLASS( iclass );
object_class->nickname = "bicubic";
object_class->description = _( "Bicubic interpolation (Catmull-Rom)" );
object_class->description = _( "bicubic interpolation (Catmull-Rom)" );
interpolate_class->interpolate = vips_interpolate_bicubic_interpolate;
interpolate_class->window_size = 4;

View File

@ -354,7 +354,7 @@ vips_interpolate_nearest_class_init( VipsInterpolateNearestClass *class )
VIPS_INTERPOLATE_CLASS( class );
object_class->nickname = "nearest";
object_class->description = _( "Nearest-neighbour interpolation" );
object_class->description = _( "nearest-neighbour interpolation" );
interpolate_class->interpolate = vips_interpolate_nearest_interpolate;
interpolate_class->window_size = 1;
@ -525,7 +525,7 @@ vips_interpolate_bilinear_class_init( VipsInterpolateBilinearClass *class )
(VipsInterpolateClass *) class;
object_class->nickname = "bilinear";
object_class->description = _( "Bilinear interpolation" );
object_class->description = _( "bilinear interpolation" );
interpolate_class->interpolate = vips_interpolate_bilinear_interpolate;
interpolate_class->window_size = 2;

View File

@ -856,7 +856,7 @@ vips_interpolate_lbb_class_init( VipsInterpolateLbbClass *klass )
VIPS_INTERPOLATE_CLASS( klass );
object_class->nickname = "lbb";
object_class->description = _( "Reduced halo bicubic" );
object_class->description = _( "reduced halo bicubic" );
interpolate_class->interpolate = vips_interpolate_lbb_interpolate;
interpolate_class->window_size = 4;

View File

@ -1577,7 +1577,7 @@ vips_interpolate_nohalo_class_init( VipsInterpolateNohaloClass *klass )
object_class->nickname = "nohalo";
object_class->description =
_( "Edge sharpening resampler with halo reduction" );
_( "edge sharpening resampler with halo reduction" );
interpolate_class->interpolate = vips_interpolate_nohalo_interpolate;
interpolate_class->window_size = 5;

View File

@ -85,6 +85,7 @@
#include <vips/vips.h>
#include <vips/debug.h>
#include <vips/internal.h>
#include "presample.h"
@ -310,6 +311,10 @@ vips_shrink_build( VipsObject *object )
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsResample *resample = VIPS_RESAMPLE( object );
VipsShrink *shrink = (VipsShrink *) object;
VipsImage **t = (VipsImage **)
vips_object_local_array( object, 1 );
VipsImage *in;
if( VIPS_OBJECT_CLASS( vips_shrink_parent_class )->build( object ) )
return( -1 );
@ -318,7 +323,9 @@ vips_shrink_build( VipsObject *object )
shrink->mh = ceil( shrink->yshrink );
shrink->np = shrink->mw * shrink->mh;
if( vips_check_noncomplex( class->nickname, resample->in ) )
in = resample->in;
if( vips_check_noncomplex( class->nickname, in ) )
return( -1 );
if( shrink->xshrink < 1.0 ||
@ -336,14 +343,20 @@ vips_shrink_build( VipsObject *object )
if( shrink->xshrink == 1.0 &&
shrink->yshrink == 1.0 )
return( vips_image_write( resample->in, resample->out ) );
return( vips_image_write( in, resample->out ) );
/* Unpack for processing.
*/
if( vips__image_decode( in, &t[0] ) )
return( -1 );
in = t[0];
/* THINSTRIP will work, anything else will break seq mode. If you
* combine shrink with conv you'll need to use a line cache to maintain
* sequentiality.
*/
if( vips_image_pipelinev( resample->out,
VIPS_DEMAND_STYLE_THINSTRIP, resample->in, NULL ) )
VIPS_DEMAND_STYLE_THINSTRIP, in, NULL ) )
return( -1 );
/* Size output. Note: we round the output width down!
@ -352,8 +365,8 @@ vips_shrink_build( VipsObject *object )
* example, vipsthumbnail knows the true shrink factor (including the
* fractional part), we just see the integer part here.
*/
resample->out->Xsize = resample->in->Xsize / shrink->xshrink;
resample->out->Ysize = resample->in->Ysize / shrink->yshrink;
resample->out->Xsize = in->Xsize / shrink->xshrink;
resample->out->Ysize = in->Ysize / shrink->yshrink;
if( resample->out->Xsize <= 0 ||
resample->out->Ysize <= 0 ) {
vips_error( class->nickname,
@ -363,7 +376,7 @@ vips_shrink_build( VipsObject *object )
#ifdef DEBUG
printf( "vips_shrink_build: shrinking %d x %d image to %d x %d\n",
resample->in->Xsize, resample->in->Ysize,
in->Xsize, in->Ysize,
resample->out->Xsize, resample->out->Ysize );
printf( "vips_shrink_build: %d x %d block average\n",
shrink->mw, shrink->mh );
@ -371,7 +384,7 @@ vips_shrink_build( VipsObject *object )
if( vips_image_generate( resample->out,
vips_shrink_start, vips_shrink_gen, vips_shrink_stop,
resample->in, shrink ) )
in, shrink ) )
return( -1 );
return( 0 );