Merge branch 'master' into add-libnsgif
This commit is contained in:
commit
d6c4d23d6c
@ -19,7 +19,6 @@
|
||||
- add "all" mode to smartcrop
|
||||
- flood fill could stop half-way for some very complex shapes
|
||||
- better handling of unaligned reads in multipage tiffs [petoor]
|
||||
- add experimental libspng reader
|
||||
- mark old --delete option to vipsthumbnail as deprecated [UweOhse]
|
||||
- png save with a bad ICC profile just gives a warning
|
||||
- add "premultipled" option to vips_affine(), clarified vips_resize()
|
||||
@ -40,6 +39,8 @@
|
||||
- rework the final bits of vips7 for vips8 [kleisauke]
|
||||
- --disable-deprecated now works [kleisauke]
|
||||
- vipsheader allows "stdin" as a filename
|
||||
- gifload allows gifs with images outside the canvas
|
||||
- wasm compatibility patches [kleisauke]
|
||||
|
||||
24/4/20 started 8.9.3
|
||||
- better iiif tile naming [IllyaMoskvin]
|
||||
|
45
README.md
45
README.md
@ -4,51 +4,6 @@
|
||||
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/libvips.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=2&q=proj:libvips)
|
||||
[![Coverity Status](https://scan.coverity.com/projects/6503/badge.svg)](https://scan.coverity.com/projects/jcupitt-libvips)
|
||||
|
||||
# This branch
|
||||
|
||||
Is for experiemtning with [libspng](https://github.com/randy408/libspng).
|
||||
|
||||
## Notes
|
||||
|
||||
Build libspng:
|
||||
|
||||
```
|
||||
cd libspng
|
||||
meson build --prefix=/home/john/vips --libdir=/home/john/vips/lib \
|
||||
--buildtype=release
|
||||
cd build
|
||||
ninja
|
||||
ninja install
|
||||
```
|
||||
|
||||
Installs `spng.pc`.
|
||||
|
||||
Sample code:
|
||||
|
||||
https://github.com/randy408/libspng/blob/master/examples/example.c
|
||||
|
||||
libspng benchmark:
|
||||
|
||||
```
|
||||
$ time vips avg wtc.png
|
||||
117.065766
|
||||
|
||||
real 0m2.972s
|
||||
user 0m3.376s
|
||||
sys 0m0.197s
|
||||
```
|
||||
|
||||
And for libpng:
|
||||
|
||||
```
|
||||
$ time vips avg wtc.png
|
||||
117.065766
|
||||
|
||||
real 0m3.816s
|
||||
user 0m4.177s
|
||||
sys 0m0.221s
|
||||
```
|
||||
|
||||
# Introduction
|
||||
|
||||
libvips is a [demand-driven, horizontally
|
||||
|
@ -96,7 +96,7 @@ vips_profile_load_build( VipsObject *object )
|
||||
else if( (data = vips__file_read_name( load->name,
|
||||
vips__icc_dir(), &length )) )
|
||||
profile = vips_blob_new(
|
||||
(VipsCallbackFn) g_free, data, length );
|
||||
(VipsCallbackFn) vips_area_free_cb, data, length );
|
||||
else {
|
||||
vips_error( class->nickname,
|
||||
_( "unable to load profile \"%s\"" ), load->name );
|
||||
|
@ -172,6 +172,14 @@ vips_extract_area_build( VipsObject *object )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
static void
|
||||
vips_crop_class_init_adapter( VipsExtractAreaClass *class, void *dummy )
|
||||
{
|
||||
vips_extract_area_class_init( class );
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
vips_extract_area_class_init( VipsExtractAreaClass *class )
|
||||
{
|
||||
@ -226,6 +234,14 @@ vips_extract_area_class_init( VipsExtractAreaClass *class )
|
||||
|
||||
}
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
static void
|
||||
vips_crop_init_adapter( VipsExtractArea *extract, void *dummy )
|
||||
{
|
||||
vips_extract_area_init( extract );
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
vips_extract_area_init( VipsExtractArea *extract )
|
||||
{
|
||||
@ -275,12 +291,20 @@ vips_crop_get_type( void )
|
||||
sizeof( VipsExtractAreaClass ),
|
||||
NULL, /* base_init */
|
||||
NULL, /* base_finalize */
|
||||
#ifdef __EMSCRIPTEN__
|
||||
(GClassInitFunc) vips_crop_class_init_adapter,
|
||||
#else
|
||||
(GClassInitFunc) vips_extract_area_class_init,
|
||||
#endif
|
||||
NULL, /* class_finalize */
|
||||
NULL, /* class_data */
|
||||
sizeof( VipsExtractArea ),
|
||||
32, /* n_preallocs */
|
||||
#ifdef __EMSCRIPTEN__
|
||||
(GInstanceInitFunc) vips_crop_init_adapter,
|
||||
#else
|
||||
(GInstanceInitFunc) vips_extract_area_init,
|
||||
#endif
|
||||
};
|
||||
|
||||
type = g_type_register_static( VIPS_TYPE_CONVERSION,
|
||||
|
@ -473,7 +473,7 @@ vips_tile_destroy( VipsTile *tile )
|
||||
|
||||
VIPS_UNREF( tile->region );
|
||||
|
||||
vips_free( tile );
|
||||
g_free( tile );
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -225,7 +225,7 @@ vips_canny_polar( VipsImage **args, VipsImage **out )
|
||||
{
|
||||
static GOnce once = G_ONCE_INIT;
|
||||
|
||||
g_once( &once, (GThreadFunc) vips_atan2_init, NULL );
|
||||
g_once( &once, vips_atan2_init, NULL );
|
||||
|
||||
*out = vips_image_new();
|
||||
if( vips_image_pipeline_array( *out,
|
||||
|
@ -123,7 +123,7 @@ lrmosaic_vec( im_object *argv )
|
||||
int balancetype = *((int *) argv[10]);
|
||||
int mwidth = *((int *) argv[11]);
|
||||
|
||||
return( vips_lrmosaic( argv[0], argv[1], argv[2],
|
||||
return( vips__lrmosaic( argv[0], argv[1], argv[2],
|
||||
bandno,
|
||||
xr, yr, xs, ys,
|
||||
halfcorrelation, halfarea,
|
||||
@ -257,7 +257,7 @@ tbmosaic_vec( im_object *argv )
|
||||
int balancetype = *((int *) argv[10]);
|
||||
int mwidth = *((int *) argv[11]);
|
||||
|
||||
return( vips_tbmosaic( argv[0], argv[1], argv[2],
|
||||
return( vips__tbmosaic( argv[0], argv[1], argv[2],
|
||||
bandno,
|
||||
x1, y1, x2, y2,
|
||||
halfcorrelation, halfarea,
|
||||
@ -367,7 +367,7 @@ lrmerge_vec( im_object *argv )
|
||||
int dy = *((int *) argv[4]);
|
||||
int mwidth = *((int *) argv[5]);
|
||||
|
||||
return( vips_lrmerge( argv[0], argv[1], argv[2], dx, dy, mwidth ) );
|
||||
return( im_lrmerge( argv[0], argv[1], argv[2], dx, dy, mwidth ) );
|
||||
}
|
||||
|
||||
/* Call im_lrmerge1 via arg vector.
|
||||
@ -421,7 +421,7 @@ tbmerge_vec( im_object *argv )
|
||||
int dy = *((int *) argv[4]);
|
||||
int mwidth = *((int *) argv[5]);
|
||||
|
||||
return( vips_tbmerge( argv[0], argv[1], argv[2], dx, dy, mwidth ) );
|
||||
return( im_tbmerge( argv[0], argv[1], argv[2], dx, dy, mwidth ) );
|
||||
}
|
||||
|
||||
/* Call im_tbmerge1 via arg vector.
|
||||
@ -594,7 +594,7 @@ correl_vec( im_object *argv )
|
||||
int *y = (int *) argv[9];
|
||||
double *correlation = (double *) argv[10];
|
||||
|
||||
return( vips_correl( argv[0], argv[1],
|
||||
return( vips__correl( argv[0], argv[1],
|
||||
xref, yref, xsec, ysec, cor, area, correlation, x, y ) );
|
||||
}
|
||||
|
||||
|
@ -910,7 +910,7 @@ im_free_vargv( im_function *fn, im_object *vargv )
|
||||
/* If there is local storage, free it.
|
||||
*/
|
||||
if( fn->argv[i].desc->size != 0 )
|
||||
vips_free( vargv[i] );
|
||||
g_free( vargv[i] );
|
||||
|
||||
/* NULL out pointer.
|
||||
*/
|
||||
|
@ -813,3 +813,13 @@ vips_autorot_get_angle( VipsImage *im )
|
||||
return( VIPS_ANGLE_D0 );
|
||||
}
|
||||
|
||||
/* The old vips_free(), now replaced by g_free() and vips_area_free_cb().
|
||||
*/
|
||||
int
|
||||
vips_free( void *buf )
|
||||
{
|
||||
g_free( buf );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
@ -5367,6 +5367,25 @@ im_tbmosaic1( IMAGE *ref, IMAGE *sec, IMAGE *out,
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_lrmerge( IMAGE *ref, IMAGE *sec, IMAGE *out,
|
||||
int dx, int dy, int mwidth )
|
||||
{
|
||||
VipsImage *x;
|
||||
|
||||
if( vips_merge( ref, sec, &x, VIPS_DIRECTION_HORIZONTAL, dx, dy,
|
||||
"mblend", mwidth,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
if( vips_image_write( x, out ) ) {
|
||||
g_object_unref( x );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( x );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_lrmerge1( IMAGE *ref, IMAGE *sec, IMAGE *out,
|
||||
int xr1, int yr1, int xs1, int ys1,
|
||||
@ -5389,6 +5408,25 @@ im_lrmerge1( IMAGE *ref, IMAGE *sec, IMAGE *out,
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_tbmerge( IMAGE *ref, IMAGE *sec, IMAGE *out,
|
||||
int dx, int dy, int mwidth )
|
||||
{
|
||||
VipsImage *x;
|
||||
|
||||
if( vips_merge( ref, sec, &x, VIPS_DIRECTION_VERTICAL, dx, dy,
|
||||
"mblend", mwidth,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
if( vips_image_write( x, out ) ) {
|
||||
g_object_unref( x );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( x );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_tbmerge1( IMAGE *ref, IMAGE *sec, IMAGE *out,
|
||||
int xr1, int yr1, int xs1, int ys1,
|
||||
|
@ -309,7 +309,7 @@ read_header( const char *header )
|
||||
if( len != sizeof( struct dsr ) ) {
|
||||
vips_error( "analyze2vips",
|
||||
"%s", _( "header file size incorrect" ) );
|
||||
vips_free( d );
|
||||
g_free( d );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
@ -354,7 +354,7 @@ read_header( const char *header )
|
||||
if( (int) len != d->hk.sizeof_hdr ) {
|
||||
vips_error( "analyze2vips",
|
||||
"%s", _( "header size incorrect" ) );
|
||||
vips_free( d );
|
||||
g_free( d );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
@ -444,7 +444,7 @@ attach_meta( VipsImage *out, struct dsr *d )
|
||||
int i;
|
||||
|
||||
vips_image_set_blob( out, "dsr",
|
||||
(VipsCallbackFn) vips_free, d, d->hk.sizeof_hdr );
|
||||
(VipsCallbackFn) vips_area_free_cb, d, d->hk.sizeof_hdr );
|
||||
|
||||
for( i = 0; i < VIPS_NUMBER( dsr_header ); i++ ) {
|
||||
switch( dsr_header[i].type ) {
|
||||
@ -514,7 +514,7 @@ vips__isanalyze( const char *filename )
|
||||
result = get_vips_properties( d, &width, &height, &bands, &fmt );
|
||||
vips_error_thaw();
|
||||
|
||||
vips_free( d );
|
||||
g_free( d );
|
||||
|
||||
return( result == 0 );
|
||||
}
|
||||
@ -538,7 +538,7 @@ vips__analyze_read_header( const char *filename, VipsImage *out )
|
||||
#endif /*DEBUG*/
|
||||
|
||||
if( get_vips_properties( d, &width, &height, &bands, &fmt ) ) {
|
||||
vips_free( d );
|
||||
g_free( d );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
|
@ -275,7 +275,7 @@ vips_gsf_tree_new( GsfOutput *out, gint deflate_level )
|
||||
}
|
||||
|
||||
static void *
|
||||
vips_gsf_child_by_name_sub( VipsGsfDirectory *dir, const char *name )
|
||||
vips_gsf_child_by_name_sub( VipsGsfDirectory *dir, const char *name, void *b )
|
||||
{
|
||||
if( strcmp( dir->name, name ) == 0 )
|
||||
return( dir );
|
||||
@ -2692,7 +2692,7 @@ vips_foreign_save_dz_buffer_build( VipsObject *object )
|
||||
gsf_output_memory_get_bytes( GSF_OUTPUT_MEMORY( dz->out ) ),
|
||||
olen );
|
||||
|
||||
blob = vips_blob_new( (VipsCallbackFn) g_free, obuf, olen );
|
||||
blob = vips_blob_new( (VipsCallbackFn) vips_area_free_cb, obuf, olen );
|
||||
g_object_set( object, "buffer", blob, NULL );
|
||||
vips_area_unref( VIPS_AREA( blob ) );
|
||||
|
||||
|
@ -1258,7 +1258,7 @@ vips_exif_exif_entry( ExifEntry *entry, VipsExifRemove *ve )
|
||||
}
|
||||
|
||||
static void *
|
||||
vips_exif_exif_remove( ExifEntry *entry, VipsExifRemove *ve )
|
||||
vips_exif_exif_remove( ExifEntry *entry, VipsExifRemove *ve, void *b )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
{
|
||||
@ -1405,7 +1405,7 @@ vips__exif_update( VipsImage *image )
|
||||
#endif /*DEBUG*/
|
||||
|
||||
vips_image_set_blob( image, VIPS_META_EXIF_NAME,
|
||||
(VipsCallbackFn) vips_free, data, length );
|
||||
(VipsCallbackFn) vips_area_free_cb, data, length );
|
||||
|
||||
exif_data_free( ed );
|
||||
|
||||
|
@ -390,7 +390,7 @@ file_add_class( VipsForeignClass *class, GSList **files )
|
||||
}
|
||||
|
||||
static gint
|
||||
file_compare( VipsForeignClass *a, VipsForeignClass *b )
|
||||
file_compare( VipsForeignClass *a, VipsForeignClass *b, void *user_data )
|
||||
{
|
||||
return( b->priority - a->priority );
|
||||
}
|
||||
@ -479,7 +479,7 @@ vips_foreign_load_summary_class( VipsObjectClass *object_class, VipsBuf *buf )
|
||||
*/
|
||||
static void *
|
||||
vips_foreign_find_load_sub( VipsForeignLoadClass *load_class,
|
||||
const char *filename )
|
||||
const char *filename, void *b )
|
||||
{
|
||||
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( load_class );
|
||||
VipsForeignClass *class = VIPS_FOREIGN_CLASS( load_class );
|
||||
@ -1763,7 +1763,7 @@ vips_foreign_save_init( VipsForeignSave *save )
|
||||
*/
|
||||
static void *
|
||||
vips_foreign_find_save_sub( VipsForeignSaveClass *save_class,
|
||||
const char *filename )
|
||||
const char *filename, void *b )
|
||||
{
|
||||
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( save_class );
|
||||
VipsForeignClass *class = VIPS_FOREIGN_CLASS( save_class );
|
||||
@ -1919,7 +1919,7 @@ vips_foreign_save( VipsImage *in, const char *name, ... )
|
||||
*/
|
||||
static void *
|
||||
vips_foreign_find_save_target_sub( VipsForeignSaveClass *save_class,
|
||||
const char *suffix )
|
||||
const char *suffix, void *b )
|
||||
{
|
||||
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( save_class );
|
||||
VipsForeignClass *class = VIPS_FOREIGN_CLASS( save_class );
|
||||
@ -1977,7 +1977,7 @@ vips_foreign_find_save_target( const char *name )
|
||||
*/
|
||||
static void *
|
||||
vips_foreign_find_save_buffer_sub( VipsForeignSaveClass *save_class,
|
||||
const char *suffix )
|
||||
const char *suffix, void *b )
|
||||
{
|
||||
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( save_class );
|
||||
VipsForeignClass *class = VIPS_FOREIGN_CLASS( save_class );
|
||||
|
@ -39,6 +39,9 @@
|
||||
* - add gifload_source
|
||||
* 5/2/20 alon-ne
|
||||
* - fix DISPOSE_BACKGROUND and DISPOSE_PREVIOUS
|
||||
* 2/7/20
|
||||
* - clip out of bounds images against canvas
|
||||
* - fix PREVIOUS handling, again
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -177,7 +180,8 @@ typedef struct _VipsForeignLoadGif {
|
||||
*/
|
||||
VipsImage *frame;
|
||||
|
||||
/* A scratch buffer the size of frame, used for rendering.
|
||||
/* A scratch buffer the size of the largest Image inside the GIF. We
|
||||
* decompress lines from the GIF to this.
|
||||
*/
|
||||
VipsImage *scratch;
|
||||
|
||||
@ -189,8 +193,10 @@ typedef struct _VipsForeignLoadGif {
|
||||
*/
|
||||
int current_page;
|
||||
|
||||
/* Decompress lines of the gif file to here.
|
||||
/* Decompress lines of the gif file to here. This is large enough to
|
||||
* hold one line of the widest sub-image in the GIF.
|
||||
*/
|
||||
int max_image_width;
|
||||
GifPixelType *line;
|
||||
|
||||
/* The current dispose method.
|
||||
@ -211,11 +217,6 @@ typedef struct _VipsForeignLoadGif {
|
||||
*/
|
||||
int transparent_index;
|
||||
|
||||
/* Params for DGifOpen(). Set by subclasses, called by base class in
|
||||
* _open().
|
||||
*/
|
||||
InputFunc read_func;
|
||||
|
||||
} VipsForeignLoadGif;
|
||||
|
||||
typedef VipsForeignLoadClass VipsForeignLoadGifClass;
|
||||
@ -400,6 +401,7 @@ vips_foreign_load_gif_open_giflib( VipsForeignLoadGif *gif )
|
||||
|
||||
gif->eof = FALSE;
|
||||
gif->current_page = 0;
|
||||
gif->max_image_width = 0;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
@ -478,8 +480,10 @@ vips_foreign_load_gif_ext_next( VipsForeignLoadGif *gif,
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VERBOSE
|
||||
if( *extension )
|
||||
VIPS_DEBUG_MSG( "gifload: EXTENSION_NEXT\n" );
|
||||
printf( "gifload: EXTENSION_NEXT\n" );
|
||||
#endif /*DEBUG_VERBOSE*/
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
@ -493,8 +497,10 @@ vips_foreign_load_gif_code_next( VipsForeignLoadGif *gif,
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VERBOSE
|
||||
if( *extension )
|
||||
VIPS_DEBUG_MSG( "gifload: CODE_NEXT\n" );
|
||||
printf( "gifload: CODE_NEXT\n" );
|
||||
#endif /*DEBUG_VERBOSE*/
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
@ -510,26 +516,33 @@ vips_foreign_load_gif_scan_image( VipsForeignLoadGif *gif )
|
||||
ColorMapObject *map;
|
||||
GifByteType *extension;
|
||||
|
||||
if( DGifGetImageDesc( gif->file ) == GIF_ERROR ) {
|
||||
if( DGifGetImageDesc( file ) == GIF_ERROR ) {
|
||||
vips_foreign_load_gif_error( gif );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* Check that the frame looks sane. Perhaps giflib checks
|
||||
* this for us.
|
||||
VIPS_DEBUG_MSG( "vips_foreign_load_gif_scan_image: "
|
||||
"frame of %dx%d pixels at %dx%d\n",
|
||||
file->Image.Width, file->Image.Height,
|
||||
file->Image.Left, file->Image.Top );
|
||||
|
||||
/* giflib does no checking of image dimensions, not even for 0.
|
||||
*/
|
||||
if( file->Image.Left < 0 ||
|
||||
file->Image.Width < 1 ||
|
||||
file->Image.Width > 10000 ||
|
||||
file->Image.Left + file->Image.Width > file->SWidth ||
|
||||
file->Image.Top < 0 ||
|
||||
file->Image.Height < 1 ||
|
||||
file->Image.Height > 10000 ||
|
||||
file->Image.Top + file->Image.Height > file->SHeight ) {
|
||||
vips_error( class->nickname, "%s", _( "bad frame size" ) );
|
||||
if( file->Image.Width <= 0 ||
|
||||
file->Image.Width > VIPS_MAX_COORD ||
|
||||
file->Image.Height <= 0 ||
|
||||
file->Image.Height > VIPS_MAX_COORD ) {
|
||||
vips_error( class->nickname,
|
||||
"%s", _( "image size out of bounds" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* We need to find the max scanline size inside the GIF
|
||||
* so we can allocate the decompress buffer.
|
||||
*/
|
||||
gif->max_image_width = VIPS_MAX( gif->max_image_width,
|
||||
file->Image.Width );
|
||||
|
||||
/* Test for a non-greyscale colourmap for this frame.
|
||||
*/
|
||||
map = file->Image.ColorMap ? file->Image.ColorMap : file->SColorMap;
|
||||
@ -713,7 +726,7 @@ vips_foreign_load_gif_set_header( VipsForeignLoadGif *gif, VipsImage *image )
|
||||
}
|
||||
|
||||
/* Attempt to quickly scan a GIF and discover what we need for our header. We
|
||||
* need to scan the whole file to get n_pages, transparency and colour.
|
||||
* need to scan the whole file to get n_pages, transparency, colour etc.
|
||||
*
|
||||
* Don't flag errors during header scan. Many GIFs do not follow spec.
|
||||
*/
|
||||
@ -769,6 +782,12 @@ vips_foreign_load_gif_scan( VipsForeignLoadGif *gif )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( gif->max_image_width <= 0 ||
|
||||
gif->max_image_width > VIPS_MAX_COORD ) {
|
||||
vips_error( class->nickname, "%s", _( "bad image size" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
@ -801,9 +820,9 @@ vips_foreign_load_gif_header( VipsForeignLoad *load )
|
||||
|
||||
/* Allocate a line buffer now that we have the GIF width.
|
||||
*/
|
||||
if( !(gif->line =
|
||||
VIPS_ARRAY( NULL, gif->file->SWidth, GifPixelType )) ||
|
||||
vips_foreign_load_gif_scan( gif ) ||
|
||||
if( vips_foreign_load_gif_scan( gif ) ||
|
||||
!(gif->line = VIPS_ARRAY( NULL,
|
||||
gif->max_image_width, GifPixelType )) ||
|
||||
vips_foreign_load_gif_set_header( gif, load->out ) ) {
|
||||
(void) vips_foreign_load_gif_close_giflib( gif );
|
||||
|
||||
@ -844,19 +863,46 @@ vips_foreign_load_gif_build_cmap( VipsForeignLoadGif *gif )
|
||||
}
|
||||
}
|
||||
|
||||
/* Paint line y from the image left/top/width/height into scratch, clipping as
|
||||
* we go.
|
||||
*/
|
||||
static void
|
||||
vips_foreign_load_gif_render_line( VipsForeignLoadGif *gif,
|
||||
int width, VipsPel * restrict dst, VipsPel * restrict src )
|
||||
int y,
|
||||
int left, int top, int width, int height,
|
||||
VipsPel *line )
|
||||
{
|
||||
guint32 * restrict idst = (guint32 *) dst;
|
||||
VipsRect canvas;
|
||||
VipsRect row;
|
||||
VipsRect overlap;
|
||||
|
||||
int x;
|
||||
/* Many GIFs have frames which lie outside the canvas. We have to
|
||||
* clip.
|
||||
*/
|
||||
canvas.left = 0;
|
||||
canvas.top = 0;
|
||||
canvas.width = gif->file->SWidth;
|
||||
canvas.height = gif->file->SHeight;
|
||||
row.left = left;
|
||||
row.top = top + y;
|
||||
row.width = width;
|
||||
row.height = height;
|
||||
vips_rect_intersectrect( &canvas, &row, &overlap );
|
||||
|
||||
for( x = 0; x < width; x++ ) {
|
||||
VipsPel v = src[x];
|
||||
if( !vips_rect_isempty( &overlap ) ) {
|
||||
VipsPel *dst = VIPS_IMAGE_ADDR( gif->scratch,
|
||||
overlap.left, overlap.top );
|
||||
guint32 * restrict idst = (guint32 *) dst;
|
||||
VipsPel * restrict src = line + overlap.left - row.left;
|
||||
|
||||
if( v != gif->transparent_index )
|
||||
idst[x] = gif->cmap[v];
|
||||
int x;
|
||||
|
||||
for( x = 0; x < overlap.width; x++ ) {
|
||||
VipsPel v = src[x];
|
||||
|
||||
if( v != gif->transparent_index )
|
||||
idst[x] = gif->cmap[v];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -873,44 +919,18 @@ vips_foreign_load_gif_render( VipsForeignLoadGif *gif )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* giflib does not check that the Left / Top / Width / Height for this
|
||||
* Image is inside the canvas.
|
||||
*
|
||||
* We could clip against the canvas, but for now, just ignore out of
|
||||
* bounds frames. Watch for int overflow too.
|
||||
*/
|
||||
if( file->Image.Left < 0 ||
|
||||
file->Image.Left > VIPS_MAX_COORD ||
|
||||
file->Image.Width <= 0 ||
|
||||
file->Image.Width > VIPS_MAX_COORD ||
|
||||
file->Image.Left + file->Image.Width > file->SWidth ||
|
||||
file->Image.Top < 0 ||
|
||||
file->Image.Top > VIPS_MAX_COORD ||
|
||||
file->Image.Height <= 0 ||
|
||||
file->Image.Height > VIPS_MAX_COORD ||
|
||||
file->Image.Top + file->Image.Height > file->SHeight ) {
|
||||
VIPS_DEBUG_MSG( "vips_foreign_load_gif_render: "
|
||||
"out of bounds frame of %d x %d pixels at %d x %d\n",
|
||||
file->Image.Width, file->Image.Height,
|
||||
file->Image.Left, file->Image.Top );
|
||||
|
||||
/* Don't flag an error -- many GIFs have this problem.
|
||||
*/
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Update the colour map for this frame.
|
||||
*/
|
||||
vips_foreign_load_gif_build_cmap( gif );
|
||||
|
||||
/* PREVIOUS means we init the frame with the last un-disposed frame.
|
||||
* So the last un-disposed frame is used as a backdrop for the new
|
||||
* frame.
|
||||
/* If this is PREVIOUS, then after we're done, we'll need to restore
|
||||
* the frame to what it was previously. Make a note of the current
|
||||
* state.
|
||||
*/
|
||||
if( gif->dispose == DISPOSE_PREVIOUS )
|
||||
memcpy( VIPS_IMAGE_ADDR( gif->scratch, 0, 0 ),
|
||||
VIPS_IMAGE_ADDR( gif->previous, 0, 0 ),
|
||||
VIPS_IMAGE_SIZEOF_IMAGE( gif->scratch ) );
|
||||
memcpy( VIPS_IMAGE_ADDR( gif->previous, 0, 0 ),
|
||||
VIPS_IMAGE_ADDR( gif->frame, 0, 0 ),
|
||||
VIPS_IMAGE_SIZEOF_IMAGE( gif->previous ) );
|
||||
|
||||
if( file->Image.Interlace ) {
|
||||
int i;
|
||||
@ -925,9 +945,6 @@ vips_foreign_load_gif_render( VipsForeignLoadGif *gif )
|
||||
|
||||
for( y = InterlacedOffset[i]; y < file->Image.Height;
|
||||
y += InterlacedJumps[i] ) {
|
||||
VipsPel *dst = VIPS_IMAGE_ADDR( gif->scratch,
|
||||
file->Image.Left, file->Image.Top + y );
|
||||
|
||||
if( DGifGetLine( gif->file,
|
||||
gif->line, file->Image.Width ) ==
|
||||
GIF_ERROR ) {
|
||||
@ -935,8 +952,12 @@ vips_foreign_load_gif_render( VipsForeignLoadGif *gif )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
vips_foreign_load_gif_render_line( gif,
|
||||
file->Image.Width, dst, gif->line );
|
||||
vips_foreign_load_gif_render_line( gif, y,
|
||||
file->Image.Left,
|
||||
file->Image.Top,
|
||||
file->Image.Width,
|
||||
file->Image.Height,
|
||||
gif->line );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -949,17 +970,18 @@ vips_foreign_load_gif_render( VipsForeignLoadGif *gif )
|
||||
file->Image.Left, file->Image.Top );
|
||||
|
||||
for( y = 0; y < file->Image.Height; y++ ) {
|
||||
VipsPel *dst = VIPS_IMAGE_ADDR( gif->scratch,
|
||||
file->Image.Left, file->Image.Top + y );
|
||||
|
||||
if( DGifGetLine( gif->file,
|
||||
gif->line, file->Image.Width ) == GIF_ERROR ) {
|
||||
vips_foreign_load_gif_error( gif );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
vips_foreign_load_gif_render_line( gif,
|
||||
file->Image.Width, dst, gif->line );
|
||||
vips_foreign_load_gif_render_line( gif, y,
|
||||
file->Image.Left,
|
||||
file->Image.Top,
|
||||
file->Image.Width,
|
||||
file->Image.Height,
|
||||
gif->line );
|
||||
}
|
||||
}
|
||||
|
||||
@ -970,39 +992,52 @@ vips_foreign_load_gif_render( VipsForeignLoadGif *gif )
|
||||
VIPS_IMAGE_SIZEOF_IMAGE( gif->frame ) );
|
||||
|
||||
if( gif->dispose == DISPOSE_BACKGROUND ) {
|
||||
/* BACKGROUND means we reset the frame to transparent before we
|
||||
* render the next set of pixels.
|
||||
/* BACKGROUND means we reset the area we just painted to
|
||||
* transparent. We have to clip against the canvas.
|
||||
*/
|
||||
guint32 *q = (guint32 *) VIPS_IMAGE_ADDR( gif->scratch,
|
||||
file->Image.Left, file->Image.Top );
|
||||
VipsRect canvas;
|
||||
VipsRect image;
|
||||
VipsRect overlap;
|
||||
|
||||
/* What we write for transparent pixels. We want RGB to be
|
||||
* 255, and A to be 0.
|
||||
*/
|
||||
guint32 ink = GUINT32_TO_BE( 0xffffff00 );
|
||||
canvas.left = 0;
|
||||
canvas.top = 0;
|
||||
canvas.width = gif->file->SWidth;
|
||||
canvas.height = gif->file->SHeight;
|
||||
image.left = file->Image.Left,
|
||||
image.top = file->Image.Top,
|
||||
image.width = file->Image.Width,
|
||||
image.height = file->Image.Height,
|
||||
vips_rect_intersectrect( &canvas, &image, &overlap );
|
||||
|
||||
int x, y;
|
||||
if( !vips_rect_isempty( &overlap ) ) {
|
||||
guint32 *q = (guint32 *) VIPS_IMAGE_ADDR( gif->scratch,
|
||||
overlap.left, overlap.top );
|
||||
|
||||
/* Generate the first line a pixel at a time, memcpy() for
|
||||
* subsequent lines.
|
||||
*/
|
||||
if( file->Image.Height > 0 )
|
||||
for( x = 0; x < file->Image.Width; x++ )
|
||||
q[x] = ink;
|
||||
/* What we write for transparent pixels. We want RGB
|
||||
* to be 255, and A to be 0.
|
||||
*/
|
||||
guint32 transparent = GUINT32_TO_BE( 0xffffff00 );
|
||||
|
||||
for( y = 1; y < file->Image.Height; y++ )
|
||||
memcpy( q + gif->scratch->Xsize * y,
|
||||
q,
|
||||
file->Image.Width * sizeof( guint32 ) );
|
||||
int x, y;
|
||||
|
||||
/* Generate the first line a pixel at a time,
|
||||
* memcpy() for subsequent lines.
|
||||
*/
|
||||
for( x = 0; x < overlap.width; x++ )
|
||||
q[x] = transparent;
|
||||
|
||||
for( y = 1; y < overlap.height; y++ )
|
||||
memcpy( q + gif->scratch->Xsize * y,
|
||||
q,
|
||||
overlap.width * sizeof( guint32 ) );
|
||||
}
|
||||
}
|
||||
else if( gif->dispose == DISPOSAL_UNSPECIFIED ||
|
||||
gif->dispose == DISPOSE_DO_NOT )
|
||||
/* Copy the frame to previous, so it can be restored if
|
||||
* DISPOSE_PREVIOUS is specified in a later frame.
|
||||
else if( gif->dispose == DISPOSE_PREVIOUS )
|
||||
/* If this is PREVIOUS, put everything back.
|
||||
*/
|
||||
memcpy( VIPS_IMAGE_ADDR( gif->previous, 0, 0 ),
|
||||
VIPS_IMAGE_ADDR( gif->frame, 0, 0 ),
|
||||
VIPS_IMAGE_SIZEOF_IMAGE( gif->previous ) );
|
||||
memcpy( VIPS_IMAGE_ADDR( gif->scratch, 0, 0 ),
|
||||
VIPS_IMAGE_ADDR( gif->previous, 0, 0 ),
|
||||
VIPS_IMAGE_SIZEOF_IMAGE( gif->scratch ) );
|
||||
|
||||
/* Reset values, as Graphic Control Extension is optional
|
||||
*/
|
||||
|
@ -334,7 +334,7 @@ readjpeg_free( ReadJpeg *jpeg )
|
||||
}
|
||||
|
||||
static void
|
||||
readjpeg_close_cb( VipsObject *object, ReadJpeg *jpeg )
|
||||
readjpeg_close_cb( VipsImage *image, ReadJpeg *jpeg )
|
||||
{
|
||||
(void) readjpeg_free( jpeg );
|
||||
}
|
||||
@ -728,7 +728,7 @@ read_jpeg_header( ReadJpeg *jpeg, VipsImage *out )
|
||||
}
|
||||
|
||||
vips_image_set_blob( out, VIPS_META_ICC_NAME,
|
||||
(VipsCallbackFn) vips_free, data, data_length );
|
||||
(VipsCallbackFn) vips_area_free_cb, data, data_length );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
|
@ -593,9 +593,7 @@ vips_foreign_save_magick_buffer_build( VipsObject *object )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* obuf is a g_free() buffer, not vips_free().
|
||||
*/
|
||||
blob = vips_blob_new( (VipsCallbackFn) g_free, obuf, olen );
|
||||
blob = vips_blob_new( (VipsCallbackFn) vips_area_free_cb, obuf, olen );
|
||||
g_object_set( buffer, "buffer", blob, NULL );
|
||||
vips_area_unref( VIPS_AREA( blob ) );
|
||||
|
||||
|
@ -92,7 +92,7 @@ read_destroy( Read *read )
|
||||
VIPS_FREEF( Mat_VarFree, read->var );
|
||||
VIPS_FREEF( Mat_Close, read->mat );
|
||||
|
||||
vips_free( read );
|
||||
g_free( read );
|
||||
}
|
||||
|
||||
static Read *
|
||||
|
@ -139,7 +139,7 @@ read_destroy( VipsImage *out, Read *read )
|
||||
|
||||
read_close( read );
|
||||
|
||||
vips_free( read );
|
||||
g_free( read );
|
||||
}
|
||||
|
||||
static Read *
|
||||
|
@ -739,13 +739,13 @@ vips__rad_israd( VipsSource *source )
|
||||
}
|
||||
|
||||
static void
|
||||
read_destroy( VipsObject *object, Read *read )
|
||||
read_destroy( VipsImage *image, Read *read )
|
||||
{
|
||||
VIPS_UNREF( read->sbuf );
|
||||
}
|
||||
|
||||
static void
|
||||
read_minimise_cb( VipsObject *object, Read *read )
|
||||
read_minimise_cb( VipsImage *image, Read *read )
|
||||
{
|
||||
if( read->sbuf )
|
||||
vips_source_minimise( read->sbuf->source );
|
||||
@ -994,7 +994,7 @@ write_destroy( Write *write )
|
||||
VIPS_FREE( write->line );
|
||||
VIPS_UNREF( write->target );
|
||||
|
||||
vips_free( write );
|
||||
g_free( write );
|
||||
}
|
||||
|
||||
static Write *
|
||||
|
@ -522,7 +522,7 @@ rtiff_free( Rtiff *rtiff )
|
||||
}
|
||||
|
||||
static void
|
||||
rtiff_close_cb( VipsObject *object, Rtiff *rtiff )
|
||||
rtiff_close_cb( VipsImage *image, Rtiff *rtiff )
|
||||
{
|
||||
rtiff_free( rtiff );
|
||||
}
|
||||
@ -1926,7 +1926,7 @@ rtiff_fill_region( VipsRegion *out,
|
||||
static int
|
||||
rtiff_seq_stop( void *seq, void *a, void *b )
|
||||
{
|
||||
vips_free( seq );
|
||||
g_free( seq );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
@ -503,10 +503,7 @@ vips_foreign_save_tiff_buffer_build( VipsObject *object )
|
||||
tiff->subifd ) )
|
||||
return( -1 );
|
||||
|
||||
/* vips__tiff_write_buf() makes a buffer that needs g_free(), not
|
||||
* vips_free().
|
||||
*/
|
||||
blob = vips_blob_new( (VipsCallbackFn) g_free, obuf, olen );
|
||||
blob = vips_blob_new( (VipsCallbackFn) vips_area_free_cb, obuf, olen );
|
||||
g_object_set( object, "buffer", blob, NULL );
|
||||
vips_area_unref( VIPS_AREA( blob ) );
|
||||
|
||||
|
@ -979,9 +979,9 @@ wtiff_free( Wtiff *wtiff )
|
||||
wtiff_delete_temps( wtiff );
|
||||
|
||||
VIPS_UNREF( wtiff->ready );
|
||||
VIPS_FREEF( vips_free, wtiff->tbuf );
|
||||
VIPS_FREE( wtiff->tbuf );
|
||||
VIPS_FREEF( layer_free_all, wtiff->layer );
|
||||
VIPS_FREEF( vips_free, wtiff->icc_profile );
|
||||
VIPS_FREE( wtiff->icc_profile );
|
||||
VIPS_FREE( wtiff->filename );
|
||||
VIPS_FREE( wtiff );
|
||||
}
|
||||
@ -1888,11 +1888,11 @@ wtiff_copy_tiff( Wtiff *wtiff, TIFF *out, TIFF *in )
|
||||
len = TIFFReadEncodedTile( in, tile, buf, -1 );
|
||||
if( len < 0 ||
|
||||
TIFFWriteEncodedTile( out, tile, buf, len ) < 0 ) {
|
||||
vips_free( buf );
|
||||
g_free( buf );
|
||||
return( -1 );
|
||||
}
|
||||
}
|
||||
vips_free( buf );
|
||||
g_free( buf );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
@ -310,6 +310,7 @@ write_webp_anim( VipsWebPWrite *write, VipsImage *image, int page_height )
|
||||
}
|
||||
|
||||
anim_config.minimize_size = write->min_size;
|
||||
anim_config.allow_mixed = write->min_size;
|
||||
anim_config.kmin = write->kmin;
|
||||
anim_config.kmax = write->kmax;
|
||||
|
||||
|
@ -294,6 +294,10 @@ void vips_vinfo( const char *domain, const char *fmt, va_list ap );
|
||||
|
||||
VipsAngle vips_autorot_get_angle( VipsImage *image );
|
||||
|
||||
/* iofuncs
|
||||
*/
|
||||
int vips_free( void *buf );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus*/
|
||||
|
@ -319,27 +319,27 @@ typedef struct _VipsImageClass {
|
||||
|
||||
/* Evaluation is starting.
|
||||
*/
|
||||
void (*preeval)( VipsImage *image, VipsProgress *progress );
|
||||
void (*preeval)( VipsImage *image, VipsProgress *progress, void *data );
|
||||
|
||||
/* Evaluation progress.
|
||||
*/
|
||||
void (*eval)( VipsImage *image, VipsProgress *progress );
|
||||
void (*eval)( VipsImage *image, VipsProgress *progress, void *data );
|
||||
|
||||
/* Evaluation is ending.
|
||||
*/
|
||||
void (*posteval)( VipsImage *image, VipsProgress *progress );
|
||||
void (*posteval)( VipsImage *image, VipsProgress *progress, void *data );
|
||||
|
||||
/* An image has been written to.
|
||||
* Used by eg. vips_image_new_mode("x.jpg", "w") to do the
|
||||
* final write to jpeg.
|
||||
* Set *result to non-zero to indicate an error on write.
|
||||
*/
|
||||
void (*written)( VipsImage *image, int *result );
|
||||
void (*written)( VipsImage *image, int *result, void *data );
|
||||
|
||||
/* An image has been modified in some way and all caches
|
||||
* need dropping.
|
||||
*/
|
||||
void (*invalidate)( VipsImage *image );
|
||||
void (*invalidate)( VipsImage *image, void *data );
|
||||
|
||||
/* Minimise this pipeline.
|
||||
*
|
||||
@ -349,7 +349,7 @@ typedef struct _VipsImageClass {
|
||||
*
|
||||
* See vips_tilecache().
|
||||
*/
|
||||
void (*minimise)( VipsImage *image );
|
||||
void (*minimise)( VipsImage *image, void *data );
|
||||
|
||||
} VipsImageClass;
|
||||
|
||||
|
@ -276,6 +276,25 @@ VipsWindow *vips_window_take( VipsWindow *window,
|
||||
|
||||
int vips__profile_set( VipsImage *image, const char *name );
|
||||
|
||||
int vips__lrmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int bandno,
|
||||
int xref, int yref, int xsec, int ysec,
|
||||
int hwindowsize, int hsearchsize,
|
||||
int balancetype,
|
||||
int mwidth );
|
||||
|
||||
int vips__tbmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int bandno,
|
||||
int xref, int yref, int xsec, int ysec,
|
||||
int hwindowsize, int hsearchsize,
|
||||
int balancetype,
|
||||
int mwidth );
|
||||
|
||||
int vips__correl( VipsImage *ref, VipsImage *sec,
|
||||
int xref, int yref, int xsec, int ysec,
|
||||
int hwindowsize, int hsearchsize,
|
||||
double *correlation, int *x, int *y );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus*/
|
||||
|
@ -66,7 +66,6 @@ G_STMT_START { \
|
||||
|
||||
void *vips_malloc( VipsObject *object, size_t size );
|
||||
char *vips_strdup( VipsObject *object, const char *str );
|
||||
int vips_free( void *buf );
|
||||
|
||||
void vips_tracked_free( void *s );
|
||||
void *vips_tracked_malloc( size_t size );
|
||||
|
@ -51,36 +51,6 @@ int vips_mosaic1( VipsImage *ref, VipsImage *sec, VipsImage **out,
|
||||
int xr2, int yr2, int xs2, int ys2, ... )
|
||||
__attribute__((sentinel));
|
||||
|
||||
/* TODO(kleisauke): Convert these to pure vips8 classes? */
|
||||
int vips_correl( VipsImage *ref, VipsImage *sec,
|
||||
int xref, int yref, int xsec, int ysec,
|
||||
int hwindowsize, int hsearchsize,
|
||||
double *correlation, int *x, int *y/*, ...*/ )
|
||||
/*__attribute__((sentinel))*/;
|
||||
|
||||
int vips_lrmerge( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int dx, int dy, int mwidth/*, ...*/ )
|
||||
/*__attribute__((sentinel))*/;
|
||||
int vips_tbmerge( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int dx, int dy, int mwidth/*, ...*/ )
|
||||
/*__attribute__((sentinel))*/;
|
||||
|
||||
int vips_lrmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int bandno,
|
||||
int xref, int yref, int xsec, int ysec,
|
||||
int hwindowsize, int hsearchsize,
|
||||
int balancetype,
|
||||
int mwidth/*, ...*/ )
|
||||
/*__attribute__((sentinel))*/;
|
||||
|
||||
int vips_tbmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int bandno,
|
||||
int xref, int yref, int xsec, int ysec,
|
||||
int hwindowsize, int hsearchsize,
|
||||
int balancetype,
|
||||
int mwidth/*, ...*/ )
|
||||
/*__attribute__((sentinel))*/;
|
||||
|
||||
int vips_match( VipsImage *ref, VipsImage *sec, VipsImage **out,
|
||||
int xr1, int yr1, int xs1, int ys1,
|
||||
int xr2, int yr2, int xs2, int ys2, ... )
|
||||
|
@ -455,7 +455,7 @@ struct _VipsObjectClass {
|
||||
|
||||
/* Just after build ... the object is fully ready for work.
|
||||
*/
|
||||
int (*postbuild)( VipsObject *object );
|
||||
int (*postbuild)( VipsObject *object, void *data );
|
||||
|
||||
/* Try to print something about the class, handy for help displays.
|
||||
* Keep to one line.
|
||||
|
@ -92,6 +92,7 @@ typedef struct _VipsArea {
|
||||
} VipsArea;
|
||||
|
||||
VipsArea *vips_area_copy( VipsArea *area );
|
||||
int vips_area_free_cb( void *mem, VipsArea *area );
|
||||
void vips_area_unref( VipsArea *area );
|
||||
|
||||
VipsArea *vips_area_new( VipsCallbackFn free_fn, void *data );
|
||||
|
@ -1065,10 +1065,14 @@ int im_global_balancef( VipsImage *in, VipsImage *out, double gamma );
|
||||
int im_remosaic( VipsImage *in, VipsImage *out,
|
||||
const char *old_str, const char *new_str );
|
||||
|
||||
int im_lrmerge( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int dx, int dy, int mwidth );
|
||||
int im_lrmerge1( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int xr1, int yr1, int xs1, int ys1,
|
||||
int xr2, int yr2, int xs2, int ys2,
|
||||
int mwidth );
|
||||
int im_tbmerge( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int dx, int dy, int mwidth );
|
||||
int im_tbmerge1( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int xr1, int yr1, int xs1, int ys1,
|
||||
int xr2, int yr2, int xs2, int ys2,
|
||||
|
@ -153,7 +153,7 @@ vips_buffer_dump( VipsBuffer *buffer, size_t *reserve, size_t *alive )
|
||||
|
||||
#ifdef DEBUG_CREATE
|
||||
static void *
|
||||
vips_buffer_cache_dump( VipsBufferCache *cache )
|
||||
vips_buffer_cache_dump( VipsBufferCache *cache, void *a, void *b )
|
||||
{
|
||||
printf( "VipsBufferCache: %p\n", cache );
|
||||
printf( "\t%d buffers\n", g_slist_length( cache->buffers ) );
|
||||
|
@ -453,7 +453,7 @@ vips_operation_equal( VipsOperation *a, VipsOperation *b )
|
||||
}
|
||||
|
||||
void *
|
||||
vips__cache_once_init( void )
|
||||
vips__cache_once_init( void *data )
|
||||
{
|
||||
vips_cache_lock = vips_g_mutex_new();
|
||||
|
||||
@ -469,7 +469,7 @@ vips__cache_init( void )
|
||||
{
|
||||
static GOnce once = G_ONCE_INIT;
|
||||
|
||||
VIPS_ONCE( &once, (GThreadFunc) vips__cache_once_init, NULL );
|
||||
VIPS_ONCE( &once, vips__cache_once_init, NULL );
|
||||
}
|
||||
|
||||
static void *
|
||||
|
@ -210,8 +210,8 @@ vips__thread_profile_init_cb( VipsThreadProfile *profile )
|
||||
vips_thread_profile_free( profile );
|
||||
}
|
||||
|
||||
static void
|
||||
vips__thread_profile_init( void )
|
||||
static void *
|
||||
vips__thread_profile_init( void *data )
|
||||
{
|
||||
#ifdef HAVE_PRIVATE_INIT
|
||||
static GPrivate private =
|
||||
@ -223,6 +223,8 @@ vips__thread_profile_init( void )
|
||||
vips_thread_profile_key = g_private_new(
|
||||
(GDestroyNotify) vips__thread_profile_init_cb );
|
||||
#endif
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
static VipsThreadGate *
|
||||
@ -245,7 +247,7 @@ vips__thread_profile_attach( const char *thread_name )
|
||||
|
||||
VipsThreadProfile *profile;
|
||||
|
||||
VIPS_ONCE( &once, (GThreadFunc) vips__thread_profile_init, NULL );
|
||||
VIPS_ONCE( &once, vips__thread_profile_init, NULL );
|
||||
|
||||
VIPS_DEBUG_MSG( "vips__thread_profile_attach: %s\n", thread_name );
|
||||
|
||||
|
@ -148,7 +148,7 @@ vips__link_make( VipsImage *image_up, VipsImage *image_down )
|
||||
}
|
||||
|
||||
static void *
|
||||
vips__link_break( VipsImage *image_up, VipsImage *image_down )
|
||||
vips__link_break( VipsImage *image_up, VipsImage *image_down, void *b )
|
||||
{
|
||||
g_assert( image_up );
|
||||
g_assert( image_down );
|
||||
@ -171,9 +171,9 @@ vips__link_break( VipsImage *image_up, VipsImage *image_down )
|
||||
}
|
||||
|
||||
static void *
|
||||
vips__link_break_rev( VipsImage *image_down, VipsImage *image_up )
|
||||
vips__link_break_rev( VipsImage *image_down, VipsImage *image_up, void *b )
|
||||
{
|
||||
return( vips__link_break( image_up, image_down ) );
|
||||
return( vips__link_break( image_up, image_down, b ) );
|
||||
}
|
||||
|
||||
/* A VipsImage is going ... break all links.
|
||||
@ -203,7 +203,7 @@ typedef struct _LinkMap {
|
||||
} LinkMap;
|
||||
|
||||
static void *
|
||||
vips__link_mapp( VipsImage *image, LinkMap *map )
|
||||
vips__link_mapp( VipsImage *image, LinkMap *map, void *b )
|
||||
{
|
||||
void *res;
|
||||
|
||||
@ -222,7 +222,7 @@ vips__link_mapp( VipsImage *image, LinkMap *map )
|
||||
}
|
||||
|
||||
static void *
|
||||
vips__link_map_cb( VipsImage *image, GSList **images )
|
||||
vips__link_map_cb( VipsImage *image, GSList **images, void *b )
|
||||
{
|
||||
*images = g_slist_prepend( *images, image );
|
||||
|
||||
@ -265,7 +265,7 @@ vips__link_map( VipsImage *image, gboolean upstream,
|
||||
serial += 1;
|
||||
map.serial = serial;
|
||||
|
||||
vips__link_mapp( image, &map );
|
||||
vips__link_mapp( image, &map, NULL );
|
||||
|
||||
for( p = images; p; p = p->next )
|
||||
g_object_ref( p->data );
|
||||
@ -494,7 +494,7 @@ vips_stop_many( void *seq, void *a, void *b )
|
||||
|
||||
for( i = 0; ar[i]; i++ )
|
||||
g_object_unref( ar[i] );
|
||||
vips_free( (char *) ar );
|
||||
g_free( (char *) ar );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
@ -630,7 +630,7 @@ vips_allocate_input_array( VipsImage *out, ... )
|
||||
/* A write function for VIPS images. Just write() the pixel data.
|
||||
*/
|
||||
static int
|
||||
write_vips( VipsRegion *region, VipsRect *area, void *a, void *b )
|
||||
write_vips( VipsRegion *region, VipsRect *area, void *a )
|
||||
{
|
||||
size_t nwritten, count;
|
||||
void *buf;
|
||||
@ -753,8 +753,7 @@ vips_image_generate( VipsImage *image,
|
||||
return( -1 );
|
||||
|
||||
if( image->dtype == VIPS_IMAGE_OPENOUT )
|
||||
res = vips_sink_disc( image,
|
||||
(VipsRegionWrite) write_vips, NULL );
|
||||
res = vips_sink_disc( image, write_vips, NULL );
|
||||
else
|
||||
res = vips_sink_memory( image );
|
||||
|
||||
|
@ -235,7 +235,7 @@ vips_format_sizeof_unsafe( VipsBandFormat format )
|
||||
/* Check that this meta is on the hash table.
|
||||
*/
|
||||
static void *
|
||||
meta_sanity_on_hash( VipsMeta *meta, VipsImage *im )
|
||||
meta_sanity_on_hash( VipsMeta *meta, VipsImage *im, void *b )
|
||||
{
|
||||
VipsMeta *found;
|
||||
|
||||
@ -970,7 +970,7 @@ vips_image_init_fields( VipsImage *image,
|
||||
}
|
||||
|
||||
static void *
|
||||
meta_cp_field( VipsMeta *meta, VipsImage *dst )
|
||||
meta_cp_field( VipsMeta *meta, VipsImage *dst, void *b )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
{
|
||||
@ -1569,7 +1569,7 @@ vips_image_set_blob_copy( VipsImage *image,
|
||||
((unsigned char *) data_copy)[length] = '\0';
|
||||
|
||||
vips_image_set_blob( image,
|
||||
name, (VipsCallbackFn) vips_free, data_copy, length );
|
||||
name, (VipsCallbackFn) vips_area_free_cb, data_copy, length );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -651,7 +651,7 @@ vips_image_summary( VipsObject *object, VipsBuf *buf )
|
||||
}
|
||||
|
||||
static void *
|
||||
vips_image_sanity_upstream( VipsImage *up, VipsImage *down )
|
||||
vips_image_sanity_upstream( VipsImage *up, VipsImage *down, void *b )
|
||||
{
|
||||
if( !g_slist_find( up->downstream, down ) ||
|
||||
!g_slist_find( down->upstream, up ) )
|
||||
@ -661,9 +661,9 @@ vips_image_sanity_upstream( VipsImage *up, VipsImage *down )
|
||||
}
|
||||
|
||||
static void *
|
||||
vips_image_sanity_downstream( VipsImage *down, VipsImage *up )
|
||||
vips_image_sanity_downstream( VipsImage *down, VipsImage *up, void *b )
|
||||
{
|
||||
return( vips_image_sanity_upstream( up, down ) );
|
||||
return( vips_image_sanity_upstream( up, down, b ) );
|
||||
}
|
||||
|
||||
static void
|
||||
@ -738,7 +738,7 @@ vips_image_rewind( VipsObject *object )
|
||||
/* From "written" callback: save to image->filename using VipsForeign.
|
||||
*/
|
||||
static void
|
||||
vips_image_save_cb( VipsImage *image, int *result )
|
||||
vips_image_save_cb( VipsImage *image, int *result, void *data )
|
||||
{
|
||||
if( vips_foreign_save( image, image->filename, NULL ) )
|
||||
*result = -1;
|
||||
@ -786,7 +786,7 @@ vips_image_eval_cb( VipsImage *image, VipsProgress *progress, int *last )
|
||||
}
|
||||
|
||||
static void
|
||||
vips_image_posteval_cb( VipsImage *image, VipsProgress *progress )
|
||||
vips_image_posteval_cb( VipsImage *image, VipsProgress *progress, void *data )
|
||||
{
|
||||
/* Spaces at end help to erase the %complete message we overwrite.
|
||||
*/
|
||||
@ -1016,7 +1016,7 @@ vips_image_build( VipsObject *object )
|
||||
}
|
||||
|
||||
static void *
|
||||
vips_image_real_invalidate_cb( VipsRegion *reg )
|
||||
vips_image_real_invalidate_cb( VipsRegion *reg, void *a, void *b )
|
||||
{
|
||||
vips_region_invalidate( reg );
|
||||
|
||||
@ -1024,7 +1024,7 @@ vips_image_real_invalidate_cb( VipsRegion *reg )
|
||||
}
|
||||
|
||||
static void
|
||||
vips_image_real_invalidate( VipsImage *image )
|
||||
vips_image_real_invalidate( VipsImage *image, void *data )
|
||||
{
|
||||
VIPS_DEBUG_MSG( "vips_image_real_invalidate: %p\n", image );
|
||||
|
||||
@ -1041,13 +1041,13 @@ vips_image_real_invalidate( VipsImage *image )
|
||||
}
|
||||
|
||||
static void
|
||||
vips_image_real_minimise( VipsImage *image )
|
||||
vips_image_real_minimise( VipsImage *image, void *data )
|
||||
{
|
||||
VIPS_DEBUG_MSG( "vips_image_real_minimise: %p\n", image );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_image_real_written( VipsImage *image, int *result )
|
||||
vips_image_real_written( VipsImage *image, int *result, void *data )
|
||||
{
|
||||
VIPS_DEBUG_MSG( "vips_image_real_written: %p\n", image );
|
||||
|
||||
@ -1390,7 +1390,7 @@ vips_image_invalidate( VipsImage *image )
|
||||
}
|
||||
|
||||
static void *
|
||||
vips_image_invalidate_all_cb( VipsImage *image )
|
||||
vips_image_invalidate_all_cb( VipsImage *image, void *a, void *b )
|
||||
{
|
||||
vips_image_invalidate( image );
|
||||
|
||||
@ -1430,7 +1430,7 @@ vips_image_minimise( VipsImage *image )
|
||||
}
|
||||
|
||||
static void *
|
||||
vips_image_minimise_all_cb( VipsImage *image )
|
||||
vips_image_minimise_all_cb( VipsImage *image, void *a, void *b )
|
||||
{
|
||||
vips_image_minimise( image );
|
||||
|
||||
|
@ -639,7 +639,7 @@ vips_leak( void )
|
||||
vips_buf_appendf( &buf, "error buffer: %s",
|
||||
vips_error_buffer() );
|
||||
|
||||
if( vips__n_active_threads != 0 )
|
||||
if( vips__n_active_threads > 0 )
|
||||
vips_buf_appendf( &buf, "threads: %d not joined\n",
|
||||
vips__n_active_threads );
|
||||
|
||||
|
@ -215,24 +215,6 @@ vips_strdup( VipsObject *object, const char *str )
|
||||
return( str_dup );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_free:
|
||||
* @buf: memory to free
|
||||
*
|
||||
* Frees memory with g_free() and returns 0. Handy for callbacks.
|
||||
*
|
||||
* See also: vips_malloc().
|
||||
*
|
||||
* Returns: 0
|
||||
*/
|
||||
int
|
||||
vips_free( void *buf )
|
||||
{
|
||||
g_free( buf );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_tracked_free:
|
||||
* @s: (transfer full): memory to free
|
||||
@ -273,10 +255,12 @@ vips_tracked_free( void *s )
|
||||
VIPS_GATE_FREE( size );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_tracked_init_mutex( void )
|
||||
static void *
|
||||
vips_tracked_init_mutex( void *data )
|
||||
{
|
||||
vips_tracked_mutex = vips_g_mutex_new();
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
static void
|
||||
@ -285,7 +269,7 @@ vips_tracked_init( void )
|
||||
static GOnce vips_tracked_once = G_ONCE_INIT;
|
||||
|
||||
VIPS_ONCE( &vips_tracked_once,
|
||||
(GThreadFunc) vips_tracked_init_mutex, NULL );
|
||||
vips_tracked_init_mutex, NULL );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1460,7 +1460,7 @@ vips_object_real_build( VipsObject *object )
|
||||
}
|
||||
|
||||
static int
|
||||
vips_object_real_postbuild( VipsObject *object )
|
||||
vips_object_real_postbuild( VipsObject *object, void *data )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf( "vips_object_real_postbuild: " );
|
||||
@ -1701,7 +1701,7 @@ traverse_find_required_priority( void *data, void *a, void *b )
|
||||
}
|
||||
|
||||
static gint
|
||||
traverse_sort( gconstpointer a, gconstpointer b )
|
||||
traverse_sort( gconstpointer a, gconstpointer b, void *user_data )
|
||||
{
|
||||
VipsArgumentClass *class1 = (VipsArgumentClass *) a;
|
||||
VipsArgumentClass *class2 = (VipsArgumentClass *) b;
|
||||
@ -1803,7 +1803,7 @@ vips_object_class_install_argument( VipsObjectClass *object_class,
|
||||
argument_table_traverse = g_slist_prepend(
|
||||
argument_table_traverse, argument_class );
|
||||
argument_table_traverse = g_slist_sort(
|
||||
argument_table_traverse, traverse_sort );
|
||||
argument_table_traverse, (GCompareFunc) traverse_sort );
|
||||
VIPS_SWAP( GSList *,
|
||||
argument_table_traverse,
|
||||
object_class->argument_table_traverse );
|
||||
@ -3045,7 +3045,7 @@ typedef struct {
|
||||
} VipsObjectLocal;
|
||||
|
||||
static void
|
||||
vips_object_local_array_cb( GObject *parent, VipsObjectLocal *local )
|
||||
vips_object_local_array_cb( VipsObject *parent, VipsObjectLocal *local )
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -3111,7 +3111,7 @@ vips_object_set_static( VipsObject *object, gboolean static_object )
|
||||
}
|
||||
|
||||
static void *
|
||||
vips_object_n_static_cb( VipsObject *object, int *n )
|
||||
vips_object_n_static_cb( VipsObject *object, int *n, void *b )
|
||||
{
|
||||
if( object->static_object )
|
||||
*n += 1;
|
||||
@ -3132,7 +3132,7 @@ vips_object_n_static( void )
|
||||
}
|
||||
|
||||
static void *
|
||||
vips_object_print_all_cb( VipsObject *object, int *n )
|
||||
vips_object_print_all_cb( VipsObject *object, int *n, void *b )
|
||||
{
|
||||
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
|
||||
|
||||
@ -3176,7 +3176,7 @@ vips_object_print_all( void )
|
||||
}
|
||||
|
||||
static void *
|
||||
vips_object_sanity_all_cb( VipsObject *object )
|
||||
vips_object_sanity_all_cb( VipsObject *object, void *a, void *b )
|
||||
{
|
||||
(void) vips_object_sanity( object );
|
||||
|
||||
|
@ -225,7 +225,7 @@ vips_rect_unionrect( const VipsRect *r1, const VipsRect *r2, VipsRect *out )
|
||||
* vips_rect_dup: (skip)
|
||||
* @r: rectangle to duplicate
|
||||
*
|
||||
* Duplicate a rect to the heap. You need to free the result with vips_free().
|
||||
* Duplicate a rect to the heap. You need to free the result with g_free().
|
||||
*
|
||||
* Returns: (transfer full): a pointer to copy of @r allocated on the heap.
|
||||
*/
|
||||
|
@ -1576,7 +1576,7 @@ vips_region_shrink( VipsRegion *from, VipsRegion *to, const VipsRect *target )
|
||||
/* Generate into a region.
|
||||
*/
|
||||
static int
|
||||
vips_region_generate( VipsRegion *reg )
|
||||
vips_region_generate( VipsRegion *reg, void *a )
|
||||
{
|
||||
VipsImage *im = reg->im;
|
||||
|
||||
@ -1659,8 +1659,7 @@ vips_region_prepare( VipsRegion *reg, const VipsRect *r )
|
||||
|
||||
switch( im->dtype ) {
|
||||
case VIPS_IMAGE_PARTIAL:
|
||||
if( vips_region_fill( reg, r,
|
||||
(VipsRegionFillFn) vips_region_generate, NULL ) )
|
||||
if( vips_region_fill( reg, r, vips_region_generate, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
break;
|
||||
@ -1716,7 +1715,7 @@ vips_region_prepare_to_generate( VipsRegion *reg,
|
||||
|
||||
/* Run sequence into reg.
|
||||
*/
|
||||
if( vips_region_generate( reg ) )
|
||||
if( vips_region_generate( reg, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
/* The generate function may not have actually made any pixels ... it
|
||||
@ -2007,7 +2006,7 @@ vips_region_invalidate( VipsRegion *reg )
|
||||
|
||||
#ifdef VIPS_DEBUG
|
||||
static void *
|
||||
vips_region_dump_all_cb( VipsRegion *region, size_t *alive )
|
||||
vips_region_dump_all_cb( VipsRegion *region, size_t *alive, void *b )
|
||||
{
|
||||
char str[2048];
|
||||
VipsBuf buf = VIPS_BUF_STATIC( str );
|
||||
|
@ -120,7 +120,7 @@ static void
|
||||
sink_area_free( SinkArea *area )
|
||||
{
|
||||
vips_semaphore_destroy( &area->n_thread );
|
||||
vips_free( area );
|
||||
g_free( area );
|
||||
}
|
||||
|
||||
static SinkArea *
|
||||
|
@ -157,7 +157,7 @@ wbuffer_free( WriteBuffer *wbuffer )
|
||||
vips_semaphore_destroy( &wbuffer->go );
|
||||
vips_semaphore_destroy( &wbuffer->nwrite );
|
||||
vips_semaphore_destroy( &wbuffer->done );
|
||||
vips_free( wbuffer );
|
||||
g_free( wbuffer );
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -126,7 +126,7 @@ static void
|
||||
sink_memory_area_free( SinkMemoryArea *area )
|
||||
{
|
||||
vips_semaphore_destroy( &area->nwrite );
|
||||
vips_free( area );
|
||||
g_free( area );
|
||||
}
|
||||
|
||||
static SinkMemoryArea *
|
||||
|
@ -206,12 +206,12 @@ render_thread_state_new( VipsImage *im, void *a )
|
||||
}
|
||||
|
||||
static void *
|
||||
tile_free( Tile *tile )
|
||||
tile_free( Tile *tile, void *a, void *b )
|
||||
{
|
||||
VIPS_DEBUG_MSG_AMBER( "tile_free\n" );
|
||||
|
||||
VIPS_UNREF( tile->region );
|
||||
vips_free( tile );
|
||||
g_free( tile );
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
@ -245,7 +245,7 @@ render_free( Render *render )
|
||||
|
||||
VIPS_UNREF( render->in );
|
||||
|
||||
vips_free( render );
|
||||
g_free( render );
|
||||
|
||||
#ifdef VIPS_DEBUG_AMBER
|
||||
render_num_renders -= 1;
|
||||
@ -454,7 +454,7 @@ vips__render_shutdown( void )
|
||||
}
|
||||
|
||||
static int
|
||||
render_dirty_sort( Render *a, Render *b )
|
||||
render_dirty_sort( Render *a, Render *b, void *user_data )
|
||||
{
|
||||
return( b->priority - a->priority );
|
||||
}
|
||||
@ -504,7 +504,7 @@ tile_equal( gconstpointer a, gconstpointer b )
|
||||
rect1->top == rect2->top );
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
render_close_cb( VipsImage *image, Render *render )
|
||||
{
|
||||
VIPS_DEBUG_MSG_AMBER( "render_close_cb\n" );
|
||||
@ -523,8 +523,6 @@ render_close_cb( VipsImage *image, Render *render )
|
||||
*/
|
||||
VIPS_DEBUG_MSG_GREEN( "render_close_cb: reschedule\n" );
|
||||
render_reschedule = TRUE;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static Render *
|
||||
@ -617,7 +615,7 @@ tile_new( Render *render )
|
||||
tile->ticks = render->ticks;
|
||||
|
||||
if( !(tile->region = vips_region_new( render->in )) ) {
|
||||
(void) tile_free( tile );
|
||||
(void) tile_free( tile, NULL, NULL );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
|
@ -1000,9 +1000,8 @@ vips_source_map( VipsSource *source, size_t *length_out )
|
||||
}
|
||||
|
||||
static int
|
||||
vips_source_map_cb( void *a, void *b )
|
||||
vips_source_map_cb( void *a, VipsArea *area )
|
||||
{
|
||||
VipsArea *area = VIPS_AREA( b );
|
||||
GObject *gobject = G_OBJECT( area->client );
|
||||
|
||||
VIPS_UNREF( gobject );
|
||||
@ -1027,7 +1026,8 @@ vips_source_map_blob( VipsSource *source )
|
||||
VipsBlob *blob;
|
||||
|
||||
if( !(buf = vips_source_map( source, &len )) ||
|
||||
!(blob = vips_blob_new( vips_source_map_cb, buf, len )) )
|
||||
!(blob = vips_blob_new( (VipsCallbackFn) vips_source_map_cb,
|
||||
buf, len )) )
|
||||
return( NULL );
|
||||
|
||||
/* The source must stay alive until the blob is done.
|
||||
|
@ -413,7 +413,7 @@ vips_target_finish( VipsTarget *target )
|
||||
data = g_byte_array_free( target->memory_buffer, FALSE );
|
||||
target->memory_buffer = NULL;
|
||||
vips_blob_set( target->blob,
|
||||
(VipsCallbackFn) g_free, data, length );
|
||||
(VipsCallbackFn) vips_area_free_cb, data, length );
|
||||
}
|
||||
else
|
||||
class->finish( target );
|
||||
|
@ -171,6 +171,14 @@ vips_area_copy( VipsArea *area )
|
||||
return( area );
|
||||
}
|
||||
|
||||
int
|
||||
vips_area_free_cb( void *mem, VipsArea *area )
|
||||
{
|
||||
g_free( mem );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
void
|
||||
vips_area_free( VipsArea *area )
|
||||
{
|
||||
@ -314,7 +322,7 @@ vips_area_new_array( GType type, size_t sizeof_type, int n )
|
||||
void *array;
|
||||
|
||||
array = g_malloc( n * sizeof_type );
|
||||
area = vips_area_new( (VipsCallbackFn) g_free, array );
|
||||
area = vips_area_new( (VipsCallbackFn) vips_area_free_cb, array );
|
||||
area->n = n;
|
||||
area->length = n * sizeof_type;
|
||||
area->type = type;
|
||||
@ -323,7 +331,7 @@ vips_area_new_array( GType type, size_t sizeof_type, int n )
|
||||
return( area );
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
vips_area_free_array_object( GObject **array, VipsArea *area )
|
||||
{
|
||||
int i;
|
||||
@ -333,6 +341,8 @@ vips_area_free_array_object( GObject **array, VipsArea *area )
|
||||
VIPS_FREE( array );
|
||||
|
||||
area->n = 0;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -556,7 +566,7 @@ vips_ref_string_new( const char *str )
|
||||
if( !g_utf8_validate( str, -1, NULL ) )
|
||||
str = "<invalid utf-8 string>";
|
||||
|
||||
area = vips_area_new( (VipsCallbackFn) g_free, g_strdup( str ) );
|
||||
area = vips_area_new( (VipsCallbackFn) vips_area_free_cb, g_strdup( str ) );
|
||||
|
||||
/* Handy place to cache this.
|
||||
*/
|
||||
@ -655,7 +665,7 @@ vips_blob_copy( const void *data, size_t length )
|
||||
|
||||
data_copy = vips_malloc( NULL, length );
|
||||
memcpy( data_copy, data, length );
|
||||
area = vips_area_new( (VipsCallbackFn) g_free, data_copy );
|
||||
area = vips_area_new( (VipsCallbackFn) vips_area_free_cb, data_copy );
|
||||
area->length = length;
|
||||
|
||||
return( (VipsBlob *) area );
|
||||
@ -737,7 +747,7 @@ transform_blob_save_string( const GValue *src_value, GValue *dest_value )
|
||||
blob = vips_value_get_blob( src_value, &length );
|
||||
if( (b64 = g_base64_encode( blob, length )) ) {
|
||||
vips_value_set_save_string( dest_value, b64 );
|
||||
vips_free( b64 );
|
||||
g_free( b64 );
|
||||
}
|
||||
else
|
||||
/* No error return from transform, but we should set it to
|
||||
@ -756,7 +766,7 @@ transform_save_string_blob( const GValue *src_value, GValue *dest_value )
|
||||
b64 = vips_value_get_save_string( src_value );
|
||||
if( (blob = g_base64_decode( b64, &length )) )
|
||||
vips_value_set_blob( dest_value,
|
||||
(VipsCallbackFn) vips_free, blob, length );
|
||||
(VipsCallbackFn) vips_area_free_cb, blob, length );
|
||||
else
|
||||
/* No error return from transform, but we should set it to
|
||||
* something.
|
||||
@ -1675,7 +1685,7 @@ vips_value_set_blob_free( GValue *value, void *data, size_t length )
|
||||
|
||||
g_assert( G_VALUE_TYPE( value ) == VIPS_TYPE_BLOB );
|
||||
|
||||
blob = vips_blob_new( (VipsCallbackFn) g_free, data, length );
|
||||
blob = vips_blob_new( (VipsCallbackFn) vips_area_free_cb, data, length );
|
||||
g_value_set_boxed( value, blob );
|
||||
vips_area_unref( VIPS_AREA( blob ) );
|
||||
}
|
||||
|
@ -222,10 +222,10 @@ vips_slist_filter( GSList *list, VipsSListMap2Fn fn, void *a, void *b )
|
||||
static void
|
||||
vips_slist_free_all_cb( void * thing, void * dummy )
|
||||
{
|
||||
vips_free( thing );
|
||||
g_free( thing );
|
||||
}
|
||||
|
||||
/* Free a g_slist of things which need vips_free()ing.
|
||||
/* Free a g_slist of things which need g_free()ing.
|
||||
*/
|
||||
void
|
||||
vips_slist_free_all( GSList *list )
|
||||
@ -815,7 +815,7 @@ vips__file_read( FILE *fp, const char *filename, size_t *length_out )
|
||||
rewind( fp );
|
||||
read = fread( str, sizeof( char ), (size_t) len, fp );
|
||||
if( read != (size_t) len ) {
|
||||
vips_free( str );
|
||||
g_free( str );
|
||||
vips_error( "vips__file_read",
|
||||
_( "error reading from file \"%s\"" ),
|
||||
filename );
|
||||
@ -944,7 +944,7 @@ vips__gvalue_copy( GValue *value )
|
||||
}
|
||||
|
||||
static void
|
||||
vips__gvalue_free( GValue *value )
|
||||
vips__gvalue_free( GValue *value, void *user_data )
|
||||
{
|
||||
g_value_unset( value );
|
||||
g_free( value );
|
||||
@ -2031,7 +2031,7 @@ vips__icc_dir( void )
|
||||
static GOnce once = G_ONCE_INIT;
|
||||
|
||||
return( (const char *) g_once( &once,
|
||||
(GThreadFunc) vips_icc_dir_once, NULL ) );
|
||||
vips_icc_dir_once, NULL ) );
|
||||
}
|
||||
|
||||
#ifdef OS_WIN32
|
||||
@ -2069,7 +2069,7 @@ vips__windows_prefix( void )
|
||||
static GOnce once = G_ONCE_INIT;
|
||||
|
||||
return( (const char *) g_once( &once,
|
||||
(GThreadFunc) vips__windows_prefix_once, NULL ) );
|
||||
vips__windows_prefix_once, NULL ) );
|
||||
}
|
||||
|
||||
char *
|
||||
|
@ -490,7 +490,7 @@ read_chunk( int fd, gint64 offset, size_t length )
|
||||
if( !(buf = vips_malloc( NULL, length + 1 )) )
|
||||
return( NULL );
|
||||
if( read( fd, buf, length ) != (ssize_t) length ) {
|
||||
vips_free( buf );
|
||||
g_free( buf );
|
||||
vips_error( "VipsImage", "%s", _( "unable to read history" ) );
|
||||
return( NULL );
|
||||
}
|
||||
@ -828,7 +828,7 @@ target_write_quotes( VipsTarget *target, const char *str )
|
||||
}
|
||||
|
||||
static void *
|
||||
build_xml_meta( VipsMeta *meta, VipsTarget *target )
|
||||
build_xml_meta( VipsMeta *meta, VipsTarget *target, void *b )
|
||||
{
|
||||
GType type = G_VALUE_TYPE( &meta->value );
|
||||
|
||||
|
@ -129,7 +129,7 @@ vips_window_free( VipsWindow *window )
|
||||
|
||||
window->im = NULL;
|
||||
|
||||
vips_free( window );
|
||||
g_free( window );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
@ -307,7 +307,7 @@ typedef struct {
|
||||
} request_t;
|
||||
|
||||
static void *
|
||||
vips_window_fits( VipsWindow *window, request_t *req )
|
||||
vips_window_fits( VipsWindow *window, request_t *req, void *b )
|
||||
{
|
||||
if( window->top <= req->top &&
|
||||
window->top + window->height >= req->top + req->height )
|
||||
|
@ -6,20 +6,20 @@ libmosaicing_la_SOURCES = \
|
||||
mosaic.c \
|
||||
match.c \
|
||||
mosaic1.c \
|
||||
chkpair.c \
|
||||
matrixinvert.c \
|
||||
global_balance.c \
|
||||
lrmerge.c \
|
||||
tbmerge.c \
|
||||
lrmosaic.c \
|
||||
tbmosaic.c \
|
||||
remosaic.c \
|
||||
im_avgdxdy.c \
|
||||
im_chkpair.c \
|
||||
im_clinear.c \
|
||||
im_improve.c \
|
||||
im_initialize.c \
|
||||
im_lrcalcon.c \
|
||||
im_lrmerge.c \
|
||||
im_lrmosaic.c \
|
||||
im_tbcalcon.c \
|
||||
im_tbmerge.c \
|
||||
im_remosaic.c \
|
||||
im_tbmosaic.c \
|
||||
global_balance.h \
|
||||
pmosaicing.h
|
||||
|
||||
|
@ -59,8 +59,7 @@
|
||||
|
||||
#include "pmosaicing.h"
|
||||
|
||||
/**
|
||||
* vips_correl:
|
||||
/* vips__correl:
|
||||
* @ref: reference image
|
||||
* @sec: secondary image
|
||||
* @xref: position in reference image
|
||||
@ -86,19 +85,19 @@
|
||||
* parts needed. Correlation is done with vips_spcor(); the position of
|
||||
* the maximum is found with vips_max().
|
||||
*
|
||||
* See also: vips_match(), vips_lrmosaic().
|
||||
* See also: vips_match(), vips__lrmosaic().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
vips_correl( VipsImage *ref, VipsImage *sec,
|
||||
vips__correl( VipsImage *ref, VipsImage *sec,
|
||||
int xref, int yref, int xsec, int ysec,
|
||||
int hwindowsize, int hsearchsize,
|
||||
double *correlation, int *x, int *y )
|
||||
{
|
||||
VipsImage *surface = vips_image_new();
|
||||
VipsImage **t = (VipsImage **)
|
||||
vips_object_local_array( VIPS_OBJECT( surface ), 4 );
|
||||
vips_object_local_array( VIPS_OBJECT( surface ), 4 );
|
||||
|
||||
VipsRect refr, secr;
|
||||
VipsRect winr, srhr;
|
||||
@ -130,9 +129,11 @@ vips_correl( VipsImage *ref, VipsImage *sec,
|
||||
/* Extract window and search area.
|
||||
*/
|
||||
if( vips_extract_area( ref, &t[0],
|
||||
wincr.left, wincr.top, wincr.width, wincr.height, NULL ) ||
|
||||
wincr.left, wincr.top, wincr.width, wincr.height,
|
||||
NULL ) ||
|
||||
vips_extract_area( sec, &t[1],
|
||||
srhcr.left, srhcr.top, srhcr.width, srhcr.height, NULL ) ) {
|
||||
srhcr.left, srhcr.top, srhcr.width, srhcr.height,
|
||||
NULL ) ) {
|
||||
g_object_unref( surface );
|
||||
return( -1 );
|
||||
}
|
||||
@ -205,7 +206,7 @@ vips__chkpair( VipsImage *ref, VipsImage *sec, TiePoints *points )
|
||||
for( i = 0; i < points->nopoints; i++ ) {
|
||||
/* Find correlation point.
|
||||
*/
|
||||
if( vips_correl( ref, sec,
|
||||
if( vips__correl( ref, sec,
|
||||
points->x_reference[i], points->y_reference[i],
|
||||
points->x_reference[i], points->y_reference[i],
|
||||
hcor, harea,
|
@ -111,6 +111,7 @@
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/transform.h>
|
||||
#include <vips/internal.h>
|
||||
|
||||
#include "pmosaicing.h"
|
||||
#include "global_balance.h"
|
||||
@ -1339,22 +1340,17 @@ make_mos_image( SymbolTable *st, JoinNode *node, transform_fn tfn, void *a )
|
||||
!(im2 = make_mos_image( st, node->arg2, tfn, a )) )
|
||||
return( NULL );
|
||||
|
||||
out = vips_image_new();
|
||||
if( vips_merge( im1, im2, &out,
|
||||
node->type == JOIN_LR ?
|
||||
VIPS_DIRECTION_HORIZONTAL :
|
||||
VIPS_DIRECTION_VERTICAL,
|
||||
-node->dx, -node->dy,
|
||||
"mblend", node->mwidth,
|
||||
NULL ) )
|
||||
return( NULL );
|
||||
vips_object_local( st->im, out );
|
||||
|
||||
vips_image_set_string( out, "mosaic-name", node->name );
|
||||
|
||||
if( node->type == JOIN_LR ) {
|
||||
if( vips_lrmerge( im1, im2, out,
|
||||
-node->dx, -node->dy, node->mwidth ) )
|
||||
return( NULL );
|
||||
}
|
||||
else {
|
||||
if( vips_tbmerge( im1, im2, out,
|
||||
-node->dx, -node->dy, node->mwidth ) )
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case JOIN_LRROTSCALE:
|
||||
@ -1414,6 +1410,7 @@ vips__build_mosaic( SymbolTable *st, VipsImage *out, transform_fn tfn, void *a )
|
||||
{
|
||||
JoinNode *root = st->root;
|
||||
VipsImage *im1, *im2;
|
||||
VipsImage *x;
|
||||
|
||||
switch( root->type ) {
|
||||
case JOIN_LR:
|
||||
@ -1422,16 +1419,19 @@ vips__build_mosaic( SymbolTable *st, VipsImage *out, transform_fn tfn, void *a )
|
||||
!(im2 = make_mos_image( st, root->arg2, tfn, a )) )
|
||||
return( -1 );
|
||||
|
||||
if( root->type == JOIN_LR ) {
|
||||
if( vips_lrmerge( im1, im2, out,
|
||||
-root->dx, -root->dy, root->mwidth ) )
|
||||
return( -1 );
|
||||
}
|
||||
else {
|
||||
if( vips_tbmerge( im1, im2, out,
|
||||
-root->dx, -root->dy, root->mwidth ) )
|
||||
return( -1 );
|
||||
if( vips_merge( im1, im2, &x,
|
||||
root->type == JOIN_LR ?
|
||||
VIPS_DIRECTION_HORIZONTAL :
|
||||
VIPS_DIRECTION_VERTICAL,
|
||||
-root->dx, -root->dy,
|
||||
"mblend", root->mwidth,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
if( vips_image_write( x, out ) ) {
|
||||
g_object_unref( x );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( x );
|
||||
|
||||
break;
|
||||
|
||||
|
@ -203,19 +203,19 @@ find_first( VipsRegion *ir, int *pos, int x, int y, int w )
|
||||
}
|
||||
|
||||
switch( im->BandFmt ) {
|
||||
case VIPS_FORMAT_UCHAR: lsearch( unsigned char ); break;
|
||||
case VIPS_FORMAT_CHAR: lsearch( signed char ); break;
|
||||
case VIPS_FORMAT_UCHAR: lsearch( unsigned char ); break;
|
||||
case VIPS_FORMAT_CHAR: lsearch( signed char ); break;
|
||||
case VIPS_FORMAT_USHORT: lsearch( unsigned short ); break;
|
||||
case VIPS_FORMAT_SHORT: lsearch( signed short ); break;
|
||||
case VIPS_FORMAT_UINT: lsearch( unsigned int ); break;
|
||||
case VIPS_FORMAT_INT: lsearch( signed int ); break;
|
||||
case VIPS_FORMAT_FLOAT: lsearch( float ); break;
|
||||
case VIPS_FORMAT_SHORT: lsearch( signed short ); break;
|
||||
case VIPS_FORMAT_UINT: lsearch( unsigned int ); break;
|
||||
case VIPS_FORMAT_INT: lsearch( signed int ); break;
|
||||
case VIPS_FORMAT_FLOAT: lsearch( float ); break;
|
||||
case VIPS_FORMAT_DOUBLE: lsearch( double ); break;
|
||||
case VIPS_FORMAT_COMPLEX: lsearch( float ); break;
|
||||
case VIPS_FORMAT_DPCOMPLEX: lsearch( double ); break;
|
||||
|
||||
default:
|
||||
vips_error( "vips_lrmerge", "%s", _( "internal error" ) );
|
||||
g_assert_not_reached();
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
@ -252,19 +252,19 @@ find_last( VipsRegion *ir, int *pos, int x, int y, int w )
|
||||
}
|
||||
|
||||
switch( im->BandFmt ) {
|
||||
case VIPS_FORMAT_UCHAR: rsearch( unsigned char ); break;
|
||||
case VIPS_FORMAT_CHAR: rsearch( signed char ); break;
|
||||
case VIPS_FORMAT_UCHAR: rsearch( unsigned char ); break;
|
||||
case VIPS_FORMAT_CHAR: rsearch( signed char ); break;
|
||||
case VIPS_FORMAT_USHORT: rsearch( unsigned short ); break;
|
||||
case VIPS_FORMAT_SHORT: rsearch( signed short ); break;
|
||||
case VIPS_FORMAT_UINT: rsearch( unsigned int ); break;
|
||||
case VIPS_FORMAT_INT: rsearch( signed int ); break;
|
||||
case VIPS_FORMAT_FLOAT: rsearch( float ); break;
|
||||
case VIPS_FORMAT_SHORT: rsearch( signed short ); break;
|
||||
case VIPS_FORMAT_UINT: rsearch( unsigned int ); break;
|
||||
case VIPS_FORMAT_INT: rsearch( signed int ); break;
|
||||
case VIPS_FORMAT_FLOAT: rsearch( float ); break;
|
||||
case VIPS_FORMAT_DOUBLE: rsearch( double ); break;
|
||||
case VIPS_FORMAT_COMPLEX: rsearch( float ); break;
|
||||
case VIPS_FORMAT_DPCOMPLEX: rsearch( double ); break;
|
||||
|
||||
default:
|
||||
vips_error( "vipslrmerge", "%s", _( "internal error" ) );
|
||||
vips_error( "lrmerge", "%s", _( "internal error" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
@ -330,7 +330,7 @@ make_firstlast( MergeInfo *inf, Overlapping *ovlap, VipsRect *oreg )
|
||||
sr.top -= ovlap->sarea.top;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips__lrmerge: making first/last for areas:\n" );
|
||||
printf( "lrmerge: making first/last for areas:\n" );
|
||||
printf( "ref: left = %d, top = %d, width = %d, height = %d\n",
|
||||
rr.left, rr.top, rr.width, rr.height );
|
||||
printf( "sec: left = %d, top = %d, width = %d, height = %d\n",
|
||||
@ -605,7 +605,7 @@ lr_blend( VipsRegion *or, MergeInfo *inf, Overlapping *ovlap, VipsRect *oreg )
|
||||
fblend( double, im->Bands * 2, pr, ps, q ); break;
|
||||
|
||||
default:
|
||||
vips_error( "vips_lrmerge", "%s", _( "internal error" ) );
|
||||
g_assert_not_reached();
|
||||
return( -1 );
|
||||
}
|
||||
}
|
||||
@ -616,7 +616,8 @@ lr_blend( VipsRegion *or, MergeInfo *inf, Overlapping *ovlap, VipsRect *oreg )
|
||||
/* Left-right blend function for VIPS_CODING_LABQ images.
|
||||
*/
|
||||
static int
|
||||
lr_blend_labpack( VipsRegion *or, MergeInfo *inf, Overlapping *ovlap, VipsRect *oreg )
|
||||
lr_blend_labpack( VipsRegion *or, MergeInfo *inf, Overlapping *ovlap,
|
||||
VipsRect *oreg )
|
||||
{
|
||||
VipsRegion *rir = inf->rir;
|
||||
VipsRegion *sir = inf->sir;
|
||||
@ -688,11 +689,12 @@ lock_free( VipsImage *image, GMutex *lock )
|
||||
}
|
||||
|
||||
/* Build basic per-call state and do some geometry calculations. Shared with
|
||||
* vips_tbmerge, so not static.
|
||||
* tbmerge, so not static.
|
||||
*/
|
||||
Overlapping *
|
||||
vips__build_mergestate( const char *domain,
|
||||
VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth )
|
||||
VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int dx, int dy, int mwidth )
|
||||
{
|
||||
VipsImage **t = (VipsImage **)
|
||||
vips_object_local_array( VIPS_OBJECT( out ), 4 );
|
||||
@ -703,14 +705,13 @@ vips__build_mergestate( const char *domain,
|
||||
|
||||
/* TODO(kleisauke): Copied from vips_insert, perhaps we
|
||||
* need a separate function for this?
|
||||
* (just like im__insert_base) */
|
||||
* (just like im__insert_base)
|
||||
*/
|
||||
if( vips_image_pio_input( ref ) ||
|
||||
vips_image_pio_input( sec ) ||
|
||||
vips_check_bands_1orn( domain,
|
||||
ref, sec ) ||
|
||||
vips_check_bands_1orn( domain, ref, sec ) ||
|
||||
vips_check_coding_known( domain, ref ) ||
|
||||
vips_check_coding_same( domain,
|
||||
ref, sec ) )
|
||||
vips_check_coding_same( domain, ref, sec ) )
|
||||
return( NULL );
|
||||
|
||||
/* Cast our input images up to a common format and bands.
|
||||
@ -809,11 +810,12 @@ vips__build_mergestate( const char *domain,
|
||||
/* Build per-call state.
|
||||
*/
|
||||
static Overlapping *
|
||||
build_lrstate( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth )
|
||||
build_lrstate( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int dx, int dy, int mwidth )
|
||||
{
|
||||
Overlapping *ovlap;
|
||||
|
||||
if( !(ovlap = vips__build_mergestate( "vips_lrmerge",
|
||||
if( !(ovlap = vips__build_mergestate( "lrmerge",
|
||||
ref, sec, out, dx, dy, mwidth )) )
|
||||
return( NULL );
|
||||
|
||||
@ -829,7 +831,7 @@ build_lrstate( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, i
|
||||
break;
|
||||
|
||||
default:
|
||||
vips_error( "vips_lrmerge", "%s", _( "unknown coding type" ) );
|
||||
vips_error( "lrmerge", "%s", _( "unknown coding type" ) );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
@ -844,9 +846,10 @@ build_lrstate( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, i
|
||||
/* Is there too much overlap? ie. right edge of ref image is greater
|
||||
* than right edge of sec image, or left > left.
|
||||
*/
|
||||
if( VIPS_RECT_RIGHT( &ovlap->rarea ) > VIPS_RECT_RIGHT( &ovlap->sarea ) ||
|
||||
if( VIPS_RECT_RIGHT( &ovlap->rarea ) >
|
||||
VIPS_RECT_RIGHT( &ovlap->sarea ) ||
|
||||
ovlap->rarea.left > ovlap->sarea.left ) {
|
||||
vips_error( "vips_lrmerge", "%s", _( "too much overlap" ) );
|
||||
vips_error( "lrmerge", "%s", _( "too much overlap" ) );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
@ -861,7 +864,7 @@ build_lrstate( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, i
|
||||
* or the sec images. Attach output to the appropriate part of the input image.
|
||||
* area is the position that ir->im occupies in the output image.
|
||||
*
|
||||
* Shared with vips_tbmerge(), so not static.
|
||||
* Shared with tbmerge, so not static.
|
||||
*/
|
||||
int
|
||||
vips__attach_input( VipsRegion *or, VipsRegion *ir, VipsRect *area )
|
||||
@ -890,10 +893,11 @@ vips__attach_input( VipsRegion *or, VipsRegion *ir, VipsRect *area )
|
||||
* above, but just do a sub-area of the output, and make sure we copy rather
|
||||
* than just pointer-fiddling. reg is the sub-area of or->valid we should do.
|
||||
*
|
||||
* Shared with vips_tbmerge(), so not static.
|
||||
* Shared with tbmerge, so not static.
|
||||
*/
|
||||
int
|
||||
vips__copy_input( VipsRegion *or, VipsRegion *ir, VipsRect *area, VipsRect *reg )
|
||||
vips__copy_input( VipsRegion *or, VipsRegion *ir,
|
||||
VipsRect *area, VipsRect *reg )
|
||||
{
|
||||
VipsRect r = *reg;
|
||||
|
||||
@ -910,8 +914,8 @@ vips__copy_input( VipsRegion *or, VipsRegion *ir, VipsRect *area, VipsRect *reg
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Generate function for merge. This is shared between vips_lrmerge() and
|
||||
* vips_tbmerge().
|
||||
/* Generate function for merge. This is shared between lrmerge and
|
||||
* tbmerge.
|
||||
*/
|
||||
int
|
||||
vips__merge_gen( VipsRegion *or, void *seq, void *a, void *b,
|
||||
@ -981,7 +985,7 @@ vips__merge_gen( VipsRegion *or, void *seq, void *a, void *b,
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Stop function. Shared with vips_tbmerge(). Free explicitly to reduce mem
|
||||
/* Stop function. Shared with tbmerge. Free explicitly to reduce mem
|
||||
* requirements quickly for large mosaics.
|
||||
*/
|
||||
int
|
||||
@ -999,7 +1003,7 @@ vips__stop_merge( void *seq, void *a, void *b )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Start function. Shared with vips_tbmerge().
|
||||
/* Start function. Shared with tbmerge.
|
||||
*/
|
||||
void *
|
||||
vips__start_merge( VipsImage *out, void *a, void *b )
|
||||
@ -1041,12 +1045,13 @@ vips__start_merge( VipsImage *out, void *a, void *b )
|
||||
}
|
||||
|
||||
int
|
||||
vips__lrmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth )
|
||||
vips__lrmerge( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int dx, int dy, int mwidth )
|
||||
{
|
||||
Overlapping *ovlap;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips__lrmerge %s %s %s %d %d %d\n",
|
||||
printf( "lrmerge %s %s %s %d %d %d\n",
|
||||
ref->filename, sec->filename, out->filename,
|
||||
dx, dy, mwidth );
|
||||
printf( "ref is %d x %d pixels\n", ref->Xsize, ref->Ysize );
|
||||
@ -1054,16 +1059,24 @@ vips__lrmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, i
|
||||
#endif
|
||||
|
||||
if( dx > 0 || dx < 1 - ref->Xsize ) {
|
||||
VipsImage *x;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips__lrmerge: no overlap, using insert\n" );
|
||||
printf( "lrmerge: no overlap, using insert\n" );
|
||||
#endif
|
||||
|
||||
/* No overlap, use insert instead.
|
||||
*/
|
||||
if( vips_insert( ref, sec, &out, -dx, -dy,
|
||||
if( vips_insert( ref, sec, &x, -dx, -dy,
|
||||
"expand", TRUE,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
if( vips_image_write( x, out ) ) {
|
||||
g_object_unref( x );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( x );
|
||||
|
||||
out->Xoffset = -dx;
|
||||
out->Yoffset = -dy;
|
||||
|
||||
@ -1083,7 +1096,8 @@ vips__lrmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, i
|
||||
out->Yoffset = -dy;
|
||||
|
||||
if( vips_image_generate( out,
|
||||
vips__start_merge, vips__merge_gen, vips__stop_merge, ovlap, NULL ) )
|
||||
vips__start_merge, vips__merge_gen, vips__stop_merge,
|
||||
ovlap, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
return ( 0 );
|
||||
@ -1109,8 +1123,9 @@ vips__add_mosaic_name( VipsImage *image )
|
||||
{
|
||||
static int global_serial = 0;
|
||||
|
||||
/* TODO(kleisauke): Could we call vips_image_temp_name instead? */
|
||||
/* Old glibs named this differently.
|
||||
*
|
||||
* TODO(kleisauke): Could we call vips_image_temp_name instead?
|
||||
*/
|
||||
int serial =
|
||||
#if GLIB_CHECK_VERSION( 2, 30, 0 )
|
||||
@ -1128,19 +1143,3 @@ vips__add_mosaic_name( VipsImage *image )
|
||||
vips_image_set_string( image, "mosaic-name", name );
|
||||
}
|
||||
|
||||
int
|
||||
vips_lrmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth )
|
||||
{
|
||||
if( vips__lrmerge( ref, sec, out, dx, dy, mwidth ) )
|
||||
return( -1 );
|
||||
|
||||
vips__add_mosaic_name( out );
|
||||
if( vips_image_history_printf( out, "#LRJOIN <%s> <%s> <%s> <%d> <%d> <%d>",
|
||||
vips__get_mosaic_name( ref ),
|
||||
vips__get_mosaic_name( sec ),
|
||||
vips__get_mosaic_name( out ),
|
||||
-dx, -dy, mwidth ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
@ -69,6 +69,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/internal.h>
|
||||
|
||||
#include "pmosaicing.h"
|
||||
|
||||
@ -241,7 +242,7 @@ vips__find_lroverlap( VipsImage *ref_in, VipsImage *sec_in, VipsImage *out,
|
||||
}
|
||||
|
||||
int
|
||||
vips_lrmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
vips__lrmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int bandno,
|
||||
int xref, int yref, int xsec, int ysec,
|
||||
int hwindowsize, int hsearchsize,
|
||||
@ -251,6 +252,7 @@ vips_lrmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int dx0, dy0;
|
||||
double scale1, angle1, dx1, dy1;
|
||||
VipsImage *dummy;
|
||||
VipsImage *x;
|
||||
|
||||
/* Correct overlap. dummy is just a placeholder used to ensure that
|
||||
* memory used by the analysis phase is freed as soon as possible.
|
||||
@ -269,8 +271,15 @@ vips_lrmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
|
||||
/* Merge left right.
|
||||
*/
|
||||
if( vips_lrmerge( ref, sec, out, dx0, dy0, mwidth ) )
|
||||
if( vips_merge( ref, sec, &x, VIPS_DIRECTION_HORIZONTAL, dx0, dy0,
|
||||
"mblend", mwidth,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
if( vips_image_write( x, out ) ) {
|
||||
g_object_unref( x );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( x );
|
||||
|
||||
return( 0 );
|
||||
}
|
@ -37,6 +37,7 @@
|
||||
#include <math.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/internal.h>
|
||||
|
||||
#include "pmosaicing.h"
|
||||
|
||||
@ -127,7 +128,7 @@ vips_match_build( VipsObject *object )
|
||||
int xs, ys;
|
||||
double cor;
|
||||
|
||||
if( vips_correl( match->ref, match->sec,
|
||||
if( vips__correl( match->ref, match->sec,
|
||||
match->xr1, match->yr1, match->xs1, match->ys1,
|
||||
match->hwindow, match->harea,
|
||||
&cor, &xs, &ys ) )
|
||||
@ -135,7 +136,7 @@ vips_match_build( VipsObject *object )
|
||||
match->xs1 = xs;
|
||||
match->ys1 = ys;
|
||||
|
||||
if( vips_correl( match->ref, match->sec,
|
||||
if( vips__correl( match->ref, match->sec,
|
||||
match->xr2, match->yr2, match->xs2, match->ys2,
|
||||
match->hwindow, match->harea,
|
||||
&cor, &xs, &ys ) )
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include "pmosaicing.h"
|
||||
|
||||
typedef struct {
|
||||
VipsOperation parent_instance;
|
||||
@ -71,13 +72,13 @@ vips_merge_build( VipsObject *object )
|
||||
|
||||
switch( merge->direction ) {
|
||||
case VIPS_DIRECTION_HORIZONTAL:
|
||||
if( vips_lrmerge( merge->ref, merge->sec, merge->out,
|
||||
if( vips__lrmerge( merge->ref, merge->sec, merge->out,
|
||||
merge->dx, merge->dy, merge->mblend ) )
|
||||
return( -1 );
|
||||
break;
|
||||
|
||||
case VIPS_DIRECTION_VERTICAL:
|
||||
if( vips_tbmerge( merge->ref, merge->sec, merge->out,
|
||||
if( vips__tbmerge( merge->ref, merge->sec, merge->out,
|
||||
merge->dx, merge->dy, merge->mblend ) )
|
||||
return( -1 );
|
||||
break;
|
||||
@ -86,6 +87,17 @@ vips_merge_build( VipsObject *object )
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
vips__add_mosaic_name( merge->out );
|
||||
if( vips_image_history_printf( merge->out,
|
||||
"#%s <%s> <%s> <%s> <%d> <%d> <%d>",
|
||||
merge->direction == VIPS_DIRECTION_HORIZONTAL ?
|
||||
"LRJOIN" : "TBJOIN",
|
||||
vips__get_mosaic_name( merge->ref ),
|
||||
vips__get_mosaic_name( merge->sec ),
|
||||
vips__get_mosaic_name( merge->out ),
|
||||
-merge->dx, -merge->dy, merge->mblend ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include <vips/vips.h>
|
||||
#include <vips/buf.h>
|
||||
#include <vips/transform.h>
|
||||
#include <vips/internal.h>
|
||||
|
||||
#include "pmosaicing.h"
|
||||
|
||||
@ -274,11 +275,11 @@ rotjoin_search( VipsImage *ref, VipsImage *sec, VipsImage *out, joinfn jfn,
|
||||
* vips__transform_set_area() has set, and move the sec tie-points
|
||||
* accordingly.
|
||||
*/
|
||||
if( vips_correl( t[0], t[2], xr1, yr1,
|
||||
if( vips__correl( t[0], t[2], xr1, yr1,
|
||||
xs3 - trn.oarea.left, ys3 - trn.oarea.top,
|
||||
halfcorrelation, halfarea, &cor1, &xs5, &ys5 ) )
|
||||
return( -1 );
|
||||
if( vips_correl( t[0], t[2], xr2, yr2,
|
||||
if( vips__correl( t[0], t[2], xr2, yr2,
|
||||
xs4 - trn.oarea.left, ys4 - trn.oarea.top,
|
||||
halfcorrelation, halfarea, &cor2, &xs6, &ys6 ) )
|
||||
return( -1 );
|
||||
@ -393,7 +394,7 @@ old_lrmosaic1( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
|
||||
/* And join to ref.
|
||||
*/
|
||||
if( vips_lrmerge( ref, t[1], out,
|
||||
if( vips_merge( ref, t[1], out, VIPS_DIRECtION_HORIZONTAL,
|
||||
-trn2.area.left, -trn2.area.top, mwidth ) )
|
||||
return( -1 );
|
||||
|
||||
|
@ -58,21 +58,17 @@
|
||||
*
|
||||
* The mosaicing functions can be grouped into layers:
|
||||
*
|
||||
* The lowest level functions are vips_correl() and vips_merge().
|
||||
* vips_correl()
|
||||
* searches a large image for a small sub-image, returning
|
||||
* the position of the best sub-image match. vips_merge()
|
||||
* The lowest level operation is vips_merge() which
|
||||
* joins two images together
|
||||
* left-right or up-down with a smooth seam.
|
||||
*
|
||||
* Next, vips_mosaic() use the
|
||||
* search function plus the two low-level merge operations to join two images
|
||||
* Next, vips_mosaic() uses
|
||||
* search functions plus the two low-level merge operations to join two images
|
||||
* given just an approximate overlap as a start point.
|
||||
*
|
||||
* The functions vips_lrmosaic1() and vips_tbmosaic1() are
|
||||
* first-order
|
||||
* analogues of the basic mosaic functions: they take two approximate
|
||||
* tie-points and use
|
||||
* vips_mosaic1() is a first-order
|
||||
* analogue of the basic mosaic functions: it takes two approximate
|
||||
* tie-points and uses
|
||||
* them to rotate and scale the right-hand or bottom image before starting to
|
||||
* join.
|
||||
*
|
||||
|
@ -122,10 +122,12 @@ void *vips__start_merge( VipsImage *out, void *, void * );
|
||||
int vips__merge_gen( VipsRegion *or, void *seq, void *a, void *,
|
||||
gboolean *stop );
|
||||
int vips__stop_merge( void *seq, void *, void * );
|
||||
|
||||
int vips__lrmerge( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int dx, int dy, int mwidth );
|
||||
int vips__tbmerge( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int dx, int dy, int mwidth );
|
||||
|
||||
int vips__lrmerge1( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
double a, double b, double dx, double dy,
|
||||
int mwidth );
|
||||
@ -133,6 +135,10 @@ int vips__tbmerge1( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
double a, double b, double dx, double dy,
|
||||
int mwidth );
|
||||
|
||||
int vips_correl( VipsImage *ref, VipsImage *sec,
|
||||
int xref, int yref, int xsec, int ysec,
|
||||
int hwindowsize, int hsearchsize,
|
||||
double *correlation, int *x, int *y );
|
||||
|
||||
#define VIPS_MAXPOINTS (60) /* VIPS_MAXPOINTS % AREAS must be zero */
|
||||
#define AREAS (3)
|
||||
|
@ -663,17 +663,30 @@ build_tbstate( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, i
|
||||
}
|
||||
|
||||
int
|
||||
vips__tbmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth )
|
||||
vips__tbmerge( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int dx, int dy, int mwidth )
|
||||
{
|
||||
Overlapping *ovlap;
|
||||
|
||||
if( dy > 0 || dy < 1 - ref->Ysize ) {
|
||||
VipsImage *x;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips__tbmerge: no overlap, using insert\n" );
|
||||
#endif
|
||||
|
||||
/* No overlap, use insert instead.
|
||||
*/
|
||||
if( vips_insert( ref, sec, &out, -dx, -dy,
|
||||
if( vips_insert( ref, sec, &x, -dx, -dy,
|
||||
"expand", TRUE,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
if( vips_image_write( x, out ) ) {
|
||||
g_object_unref( x );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( x );
|
||||
|
||||
out->Xoffset = -dx;
|
||||
out->Yoffset = -dy;
|
||||
|
||||
@ -699,19 +712,3 @@ vips__tbmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, i
|
||||
return ( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
vips_tbmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth )
|
||||
{
|
||||
if( vips__tbmerge( ref, sec, out, dx, dy, mwidth ) )
|
||||
return( -1 );
|
||||
|
||||
vips__add_mosaic_name( out );
|
||||
if( vips_image_history_printf( out, "#TBJOIN <%s> <%s> <%s> <%d> <%d> <%d>",
|
||||
vips__get_mosaic_name( ref ),
|
||||
vips__get_mosaic_name( sec ),
|
||||
vips__get_mosaic_name( out ),
|
||||
-dx, -dy, mwidth ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
@ -213,7 +213,7 @@ vips__find_tboverlap( VipsImage *ref_in, VipsImage *sec_in, VipsImage *out,
|
||||
}
|
||||
|
||||
int
|
||||
vips_tbmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
vips__tbmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int bandno,
|
||||
int xref, int yref, int xsec, int ysec,
|
||||
int hwindowsize, int hsearchsize,
|
||||
@ -223,6 +223,7 @@ vips_tbmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int dx0, dy0;
|
||||
double scale1, angle1, dx1, dy1;
|
||||
VipsImage *dummy;
|
||||
VipsImage *x;
|
||||
|
||||
/* Correct overlap. dummy is just a placeholder used to ensure that
|
||||
* memory used by the analysis phase is freed as soon as possible.
|
||||
@ -241,8 +242,15 @@ vips_tbmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
|
||||
/* Merge top-bottom.
|
||||
*/
|
||||
if( vips_tbmerge( ref, sec, out, dx0, dy0, mwidth ) )
|
||||
if( vips_merge( ref, sec, &x, VIPS_DIRECTION_VERTICAL, dx0, dy0,
|
||||
"mblend", mwidth,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
if( vips_image_write( x, out ) ) {
|
||||
g_object_unref( x );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( x );
|
||||
|
||||
return( 0 );
|
||||
}
|
@ -349,25 +349,25 @@ libvips/morphology/morph.c
|
||||
libvips/morphology/morphology.c
|
||||
libvips/morphology/nearest.c
|
||||
libvips/morphology/rank.c
|
||||
libvips/mosaicing/chkpair.c
|
||||
libvips/mosaicing/global_balance.c
|
||||
libvips/mosaicing/im_avgdxdy.c
|
||||
libvips/mosaicing/im_chkpair.c
|
||||
libvips/mosaicing/im_clinear.c
|
||||
libvips/mosaicing/im_improve.c
|
||||
libvips/mosaicing/im_initialize.c
|
||||
libvips/mosaicing/im_lrcalcon.c
|
||||
libvips/mosaicing/im_lrmerge.c
|
||||
libvips/mosaicing/im_lrmosaic.c
|
||||
libvips/mosaicing/im_remosaic.c
|
||||
libvips/mosaicing/im_tbcalcon.c
|
||||
libvips/mosaicing/im_tbmerge.c
|
||||
libvips/mosaicing/im_tbmosaic.c
|
||||
libvips/mosaicing/lrmerge.c
|
||||
libvips/mosaicing/lrmosaic.c
|
||||
libvips/mosaicing/match.c
|
||||
libvips/mosaicing/matrixinvert.c
|
||||
libvips/mosaicing/merge.c
|
||||
libvips/mosaicing/mosaic1.c
|
||||
libvips/mosaicing/mosaic.c
|
||||
libvips/mosaicing/mosaicing.c
|
||||
libvips/mosaicing/remosaic.c
|
||||
libvips/mosaicing/tbmerge.c
|
||||
libvips/mosaicing/tbmosaic.c
|
||||
libvips/resample/affine.c
|
||||
libvips/resample/bicubic.cpp
|
||||
libvips/resample/interpolate.c
|
||||
|
@ -16,21 +16,24 @@ class TestMosaicing:
|
||||
|
||||
im = pyvips.Image.new_from_file(files[0])
|
||||
sec_im = pyvips.Image.new_from_file(files[1])
|
||||
horizontal_part = im.mosaic(sec_im, pyvips.Direction.HORIZONTAL,
|
||||
marks[0][0], marks[0][1], marks[1][0], marks[1][1])
|
||||
horizontal_part = im.mosaic(sec_im,
|
||||
pyvips.Direction.HORIZONTAL,
|
||||
marks[0][0], marks[0][1],
|
||||
marks[1][0], marks[1][1])
|
||||
|
||||
if mosaiced_image is None:
|
||||
mosaiced_image = horizontal_part
|
||||
else:
|
||||
vertical_marks = MOSAIC_VERTICAL_MARKS[i - 2:i]
|
||||
mosaiced_image = mosaiced_image.mosaic(horizontal_part, pyvips.Direction.VERTICAL,
|
||||
vertical_marks[1][0], vertical_marks[1][1],
|
||||
vertical_marks[0][0], vertical_marks[0][1])
|
||||
mosaiced_image = mosaiced_image.mosaic(horizontal_part,
|
||||
pyvips.Direction.VERTICAL,
|
||||
vertical_marks[1][0], vertical_marks[1][1],
|
||||
vertical_marks[0][0], vertical_marks[0][1])
|
||||
|
||||
mosaiced_image = mosaiced_image.globalbalance()
|
||||
mosaiced_image = mosaiced_image.globalbalance()
|
||||
|
||||
# Uncomment to see output file
|
||||
# mosaiced_image.write_to_file('1-pt-mosaic.jpg')
|
||||
#mosaiced_image.write_to_file('after.jpg')
|
||||
|
||||
# hard to test much more than this
|
||||
assert mosaiced_image.width == 1005
|
||||
|
Loading…
Reference in New Issue
Block a user