Merge branch 'dzsave-metadata' of github.com:jcupitt/libvips into dzsave-metadata

Conflicts:
	ChangeLog
	configure.ac
This commit is contained in:
John Cupitt 2014-07-01 08:47:50 +01:00
commit fc14733b2b
12 changed files with 216 additions and 46 deletions

View File

@ -1,5 +1,18 @@
<<<<<<< HEAD
26/6/14 started 7.40.2 26/6/14 started 7.40.2
- fixes to help freebsd - fixes to help freebsd
=======
30/6/14 started 7.40.3
- fix interlaced thumbnails in vipsthumbnail, thanks lovell
- add --properties argument to dzsave, thanks bgilbert
25/6/14 started 7.40.2
- dzsave write to zip stops at 4gb, thanks bgilbert
- improve short option name handling, thanks bgilbert
- added --enable-docs configure option to help freebsd
- removed a bash-ism from configure to help freebsd
- don't assume GType fits in an int to help freebsd
>>>>>>> c5fbe6daa642b522c54b6912b22649f59c8d237f
24/6/14 started 7.40.1 24/6/14 started 7.40.1
- revise man.1 pages - revise man.1 pages

View File

@ -19,6 +19,14 @@ P_COMPILE_DIR =
P_DIST_DIR = swig P_DIST_DIR = swig
endif endif
if ENABLE_DOCS
D_DIST_DIR =
D_BUILD_DIR = doc
else
D_DIST_DIR = doc
D_BUILD_DIR =
endif
SUBDIRS = \ SUBDIRS = \
libvips \ libvips \
tools \ tools \
@ -26,7 +34,8 @@ SUBDIRS = \
man \ man \
doc \ doc \
$(C_COMPILE_DIR) \ $(C_COMPILE_DIR) \
$(P_COMPILE_DIR) $(P_COMPILE_DIR) \
$(D_BUILD_DIR)
EXTRA_DIST = \ EXTRA_DIST = \
m4 \ m4 \
@ -38,15 +47,18 @@ EXTRA_DIST = \
acinclude.m4 \ acinclude.m4 \
depcomp \ depcomp \
$(C_DIST_DIR) \ $(C_DIST_DIR) \
$(P_DIST_DIR) $(P_DIST_DIR) \
$(D_DIST_DIR)
pkgconfigdir = $(libdir)/pkgconfig pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = vips.pc $(C_PKGCONFIG) pkgconfig_DATA = vips.pc $(C_PKGCONFIG)
if ENABLE_DOCS
install-exec-hook: install-exec-hook:
-rm -rf ${DESTDIR}$(datadir)/doc/vips -rm -rf ${DESTDIR}$(datadir)/doc/vips
$(mkinstalldirs) ${DESTDIR}$(datadir)/doc/vips $(mkinstalldirs) ${DESTDIR}$(datadir)/doc/vips
-cp -r ${top_srcdir}/doc/html ${top_srcdir}/doc/pdf ${DESTDIR}$(datadir)/doc/vips -cp -r ${top_srcdir}/doc/html ${top_srcdir}/doc/pdf ${DESTDIR}$(datadir)/doc/vips
endif
dist-hook: dist-hook:
# make sure we don't get any .svn dirs from EXTRA_DIST # make sure we don't get any .svn dirs from EXTRA_DIST

View File

@ -109,8 +109,9 @@ Static analysis with:
# Dependencies # Dependencies
libvips has to have gettext, glib-2.x and libxml-2.0. The build system needs libvips has to have gettext, glib-2.x and libxml-2.0. The build system
sh, pkg-config, swig, gtk-doc-tools, automake, gobject-introspection and gnu make. needs sh, pkg-config, swig, gtk-doc-tools, automake, gobject-introspection
and gnu make.
# Optional dependencies # Optional dependencies
@ -155,10 +156,6 @@ If available, libvips adds support for creating image pyramids with dzsave.
The TIFF library. It needs to be built with support for JPEG and The TIFF library. It needs to be built with support for JPEG and
ZIP compression. 3.4b037 and later are known to be OK. ZIP compression. 3.4b037 and later are known to be OK.
## libz
If your TIFF library includes ZIP compression, you'll need this too.
## fftw3 ## fftw3
If libvips finds this library, it uses it for fourier transforms. It If libvips finds this library, it uses it for fourier transforms. It

4
TODO
View File

@ -14,6 +14,8 @@
gtk-doc now used markdown, phew, use this to expand some sections gtk-doc now used markdown, phew, use this to expand some sections
- can we use postbuild elsewhere? look at use of "preclose" / "written", etc. - can we use postbuild elsewhere? look at use of "preclose" / "written", etc.
@ -36,7 +38,9 @@
- vips_getpoint() needs an optional imag return - vips_getpoint() needs an optional imag return
- add porter-duff compositing, see
https://github.com/jcupitt/ruby-vips/issues/28
- now vips_linear() has uchar output, can we do something with orc? - now vips_linear() has uchar output, can we do something with orc?

View File

@ -2,7 +2,7 @@
# also update the version number in the m4 macros below # also update the version number in the m4 macros below
AC_INIT([vips], [7.40.2], [vipsip@jiscmail.ac.uk]) AC_INIT([vips], [7.40.3], [vipsip@jiscmail.ac.uk])
# required for gobject-introspection # required for gobject-introspection
AC_PREREQ(2.62) AC_PREREQ(2.62)
@ -18,7 +18,7 @@ AC_CONFIG_MACRO_DIR([m4])
# user-visible library versioning # user-visible library versioning
m4_define([vips_major_version], [7]) m4_define([vips_major_version], [7])
m4_define([vips_minor_version], [40]) m4_define([vips_minor_version], [40])
m4_define([vips_micro_version], [2]) m4_define([vips_micro_version], [3])
m4_define([vips_version], m4_define([vips_version],
[vips_major_version.vips_minor_version.vips_micro_version]) [vips_major_version.vips_minor_version.vips_micro_version])
@ -37,8 +37,8 @@ VIPS_VERSION_STRING=$VIPS_VERSION-`date`
# binary interface changes backwards compatible?: increment age # binary interface changes backwards compatible?: increment age
# binary interface changes not backwards compatible?: reset age to 0 # binary interface changes not backwards compatible?: reset age to 0
LIBRARY_CURRENT=37 LIBRARY_CURRENT=38
LIBRARY_REVISION=5 LIBRARY_REVISION=1
LIBRARY_AGE=0 LIBRARY_AGE=0
# patched into include/vips/version.h # patched into include/vips/version.h
@ -124,6 +124,23 @@ else
fi fi
fi fi
# we are a C library with some optional C++ components inside it
# on most platforms, we just include -lstdc++ in the link line for programs
# using vips, but not all
# we ought to write a proper configure test for this :(
AC_MSG_CHECKING([for needs -lstdc++])
case "$host_os" in
freebsd*)
vips_needs_stdcpp=no
;;
*)
vips_needs_stdcpp=yes
;;
esac
AC_MSG_RESULT([$vips_needs_stdcpp])
AC_MSG_CHECKING([for native Win32]) AC_MSG_CHECKING([for native Win32])
case "$host" in case "$host" in
*-*-mingw*) *-*-mingw*)
@ -190,6 +207,20 @@ else
fi fi
AC_DEFINE_UNQUOTED(VIPS_ICC_DIR,"$profile_dir",[default directory for ICC profiles]) AC_DEFINE_UNQUOTED(VIPS_ICC_DIR,"$profile_dir",[default directory for ICC profiles])
# option to stop docs installing ... eg. freebsd likes this
AC_ARG_ENABLE(docs,
AS_HELP_STRING([--enable-docs], [install docs (default: yes)]))
if test x"$enable_docs" != x"no"; then
AM_CONDITIONAL(ENABLE_DOCS, true)
enable_docs=yes
fi
if test x"$enable_docs" != x"yes"; then
AM_CONDITIONAL(ENABLE_DOCS, false)
enable_docs=no
fi
# we want largefile support, if possible # we want largefile support, if possible
AC_SYS_LARGEFILE AC_SYS_LARGEFILE
@ -233,7 +264,9 @@ if test x"$enable_cxx" != x"no"; then
# need -lstdc++ for (eg.) the C++ format loaders # need -lstdc++ for (eg.) the C++ format loaders
# this gets added to vips.pc to help mingw and friends link programs # this gets added to vips.pc to help mingw and friends link programs
# using libvips # using libvips
if test x"$vips_needs_stdcpp" != x"no"; then
VIPS_CXX_LIBS="-lstdc++" VIPS_CXX_LIBS="-lstdc++"
fi
enable_cxx=yes enable_cxx=yes
fi fi
fi fi
@ -350,7 +383,7 @@ PKG_CHECK_MODULES(THREADS, glib-2.0 >= 2.32,[
] ]
) )
# after 2.36 the type system inits itself # with 2.36 and after the type system inits itself
PKG_CHECK_MODULES(TYPE_INIT, glib-2.0 < 2.36,[ PKG_CHECK_MODULES(TYPE_INIT, glib-2.0 < 2.36,[
AC_DEFINE(NEED_TYPE_INIT,1,[define if your glib needs g_type_init().]) AC_DEFINE(NEED_TYPE_INIT,1,[define if your glib needs g_type_init().])
],[ ],[
@ -775,6 +808,7 @@ open files in binary mode: $vips_binary_open
enable debug: $enable_debug enable debug: $enable_debug
build C++ components: $enable_cxx build C++ components: $enable_cxx
build docs with gtkdoc: $enable_gtk_doc build docs with gtkdoc: $enable_gtk_doc
install docs: $enable_docs
gobject introspection: $found_introspection gobject introspection: $found_introspection
* optional packages and modules * optional packages and modules

View File

@ -123,6 +123,9 @@ vips_compass_build( VipsObject *object )
break; break;
default: default:
/* Silence compiler wrning.
*/
x = NULL;
g_assert( 0 ); g_assert( 0 );
} }

View File

@ -43,7 +43,8 @@
* - set Type on strips so we can convert for save correctly, thanks * - set Type on strips so we can convert for save correctly, thanks
* philipgiuliani * philipgiuliani
* 25/6/14 * 25/6/14
* - save openslide metadata to .dzi, see * - stop on zip write >4gb, thanks bgilbert
* - save metadata to .dzi, see
* https://github.com/jcupitt/libvips/issues/137 * https://github.com/jcupitt/libvips/issues/137
*/ */
@ -166,6 +167,7 @@ typedef struct _VipsGsfDirectory {
* this on cleanup. * this on cleanup.
*/ */
GsfOutput *container; GsfOutput *container;
} VipsGsfDirectory; } VipsGsfDirectory;
/* Close all dirs, non-NULL on error. /* Close all dirs, non-NULL on error.
@ -389,6 +391,7 @@ struct _VipsForeignSaveDz {
VipsArrayDouble *background; VipsArrayDouble *background;
VipsForeignDzDepth depth; VipsForeignDzDepth depth;
gboolean centre; gboolean centre;
gboolean properties;
VipsAngle angle; VipsAngle angle;
VipsForeignDzContainer container; VipsForeignDzContainer container;
@ -420,6 +423,11 @@ struct _VipsForeignSaveDz {
* becomes ".jpg". * becomes ".jpg".
*/ */
char *file_suffix; char *file_suffix;
/* libgsf can't write zip files larger than 4gb. Track bytes written
* here and try to guess when we'll go over.
*/
size_t bytes_written;
}; };
typedef VipsForeignSaveClass VipsForeignSaveDzClass; typedef VipsForeignSaveClass VipsForeignSaveDzClass;
@ -706,8 +714,10 @@ write_vips_property( VipsImage *image,
char *str_value; char *str_value;
str_value = g_strdup_value_contents( value ); str_value = g_strdup_value_contents( value );
gsf_output_printf( out, " <property>\n" );
gsf_output_printf( out, " <name>%s</name>\n", field ); gsf_output_printf( out, " <name>%s</name>\n", field );
gsf_output_printf( out, " <value>%s</value>\n", str_value ); gsf_output_printf( out, " <value>%s</value>\n", str_value );
gsf_output_printf( out, " </property>\n" );
g_free( str_value ); g_free( str_value );
return( NULL ); return( NULL );
@ -718,14 +728,26 @@ write_vips_properties( VipsForeignSaveDz *dz )
{ {
VipsForeignSave *save = (VipsForeignSave *) dz; VipsForeignSave *save = (VipsForeignSave *) dz;
time_t now;
char time_string[50];
GsfOutput *out; GsfOutput *out;
time( &now );
strftime( time_string, sizeof( time_string ),
"%FT%TZ", gmtime( &now ) );
out = vips_gsf_path( dz->tree, out = vips_gsf_path( dz->tree,
"vips-properties.xml", dz->root_name, NULL ); "vips-properties.xml", dz->root_name, NULL );
gsf_output_printf( out, gsf_output_printf( out,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ); "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
gsf_output_printf( out, "<image>\n" ); gsf_output_printf( out, "<image\n" );
gsf_output_printf( out, " version=\"%s\"\n", VIPS_VERSION );
gsf_output_printf( out, " date=\"%s\"\n", time_string );
gsf_output_printf( out, " "
"xmlns=\"http://www.vips.ecs.soton.ac.uk/vips/%s\"\n",
VIPS_VERSION );
gsf_output_printf( out, " >\n" );
gsf_output_printf( out, " <properties>\n" ); gsf_output_printf( out, " <properties>\n" );
(void) vips_image_map( save->ready, write_vips_property, out ); (void) vips_image_map( save->ready, write_vips_property, out );
gsf_output_printf( out, " </properties>\n" ); gsf_output_printf( out, " </properties>\n" );
@ -1039,12 +1061,14 @@ strip_work( VipsThreadState *state, void *a )
Strip *strip = (Strip *) a; Strip *strip = (Strip *) a;
Layer *layer = strip->layer; Layer *layer = strip->layer;
VipsForeignSaveDz *dz = layer->dz; VipsForeignSaveDz *dz = layer->dz;
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( dz );
VipsImage *x; VipsImage *x;
VipsImage *t; VipsImage *t;
void *buf; void *buf;
size_t len; size_t len;
GsfOutput *out; GsfOutput *out;
gboolean status;
#ifdef DEBUG_VERBOSE #ifdef DEBUG_VERBOSE
printf( "strip_work\n" ); printf( "strip_work\n" );
@ -1115,13 +1139,36 @@ strip_work( VipsThreadState *state, void *a )
out = tile_name( layer, out = tile_name( layer,
state->x / dz->tile_size, state->y / dz->tile_size ); state->x / dz->tile_size, state->y / dz->tile_size );
gsf_output_write( out, len, buf ); status = gsf_output_write( out, len, buf );
dz->bytes_written += len;
gsf_output_close( out ); gsf_output_close( out );
g_object_unref( out ); g_object_unref( out );
g_free( buf );
if( !status ) {
g_mutex_unlock( vips__global_lock ); g_mutex_unlock( vips__global_lock );
g_free( buf ); vips_error( class->nickname,
"%s", gsf_output_error( out )->message );
return( -1 );
}
/* Allow a 100,000 byte margin. This probably isn't enough: we don't
* include the space zip needs for the index nor anything we are
* outputting apart from the gsf_output_write() above.
*/
if( dz->container == VIPS_FOREIGN_DZ_CONTAINER_ZIP &&
dz->bytes_written > (size_t) UINT_MAX - 100000 ) {
g_mutex_unlock( vips__global_lock );
vips_error( class->nickname,
"%s", _( "output file too large" ) );
return( -1 );
}
g_mutex_unlock( vips__global_lock );
#ifdef DEBUG_VERBOSE #ifdef DEBUG_VERBOSE
printf( "strip_work: success\n" ); printf( "strip_work: success\n" );
@ -1666,7 +1713,8 @@ vips_foreign_save_dz_build( VipsObject *object )
return( -1 ); return( -1 );
} }
if( write_vips_properties( dz ) ) if( dz->properties &&
write_vips_properties( dz ) )
return( -1 ); return( -1 );
if( vips_gsf_tree_close( dz->tree ) ) if( vips_gsf_tree_close( dz->tree ) )
@ -1821,6 +1869,13 @@ vips_foreign_save_dz_class_init( VipsForeignSaveDzClass *class )
VIPS_TYPE_FOREIGN_DZ_CONTAINER, VIPS_TYPE_FOREIGN_DZ_CONTAINER,
VIPS_FOREIGN_DZ_CONTAINER_FS ); VIPS_FOREIGN_DZ_CONTAINER_FS );
VIPS_ARG_BOOL( class, "properties", 16,
_( "Properties" ),
_( "Write a properties file to the output directory" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveDz, properties ),
FALSE );
/* How annoying. We stupidly had these in earlier versions. /* How annoying. We stupidly had these in earlier versions.
*/ */
@ -1886,16 +1941,17 @@ vips_foreign_save_dz_init( VipsForeignSaveDz *dz )
* @centre: centre the tiles * @centre: centre the tiles
* @angle: rotate the image by this much * @angle: rotate the image by this much
* @container: set container type * @container: set container type
* @properties: write a properties file
* *
* Save an image as a set of tiles at various resolutions. By default dzsave * Save an image as a set of tiles at various resolutions. By default dzsave
* uses DeepZoom layout -- use @layout to pick other conventions. * uses DeepZoom layout -- use @layout to pick other conventions.
* *
* vips_dzsave() creates a directory called @name to hold the tiles. If @name * vips_dzsave() creates a directory called @name to hold the tiles. If @name
* ends ".zip", vips_dzsave() will create a zip file called @name to hold the * ends `.zip`, vips_dzsave() will create a zip file called @name to hold the
* tiles. You can use @container to force zip file output. * tiles. You can use @container to force zip file output.
* *
* You can set @suffix to something like ".jpg[Q=85]" to control the tile write * You can set @suffix to something like `".jpg[Q=85]"` to control the tile
* options. * write options.
* *
* In Google layout mode, edge tiles are expanded to @tile_size by @tile_size * In Google layout mode, edge tiles are expanded to @tile_size by @tile_size
* pixels. Normally they are filled with white, but you can set another colour * pixels. Normally they are filled with white, but you can set another colour
@ -1908,6 +1964,12 @@ vips_foreign_save_dz_init( VipsForeignSaveDz *dz )
* Use @depth to control how low the pyramid goes. This defaults to the * Use @depth to control how low the pyramid goes. This defaults to the
* correct setting for the @layout you select. * correct setting for the @layout you select.
* *
* If @properties is %TRUE, vips_dzsave() will write a file called
* `vips-properties.xml` to the output directory. This file lists all of the
* metadata attached to @in in an obvious manner. It can be useful for viewing
* programs which wish to use fields from source files loaded via
* vips_openslideload().
*
* See also: vips_tiffsave(). * See also: vips_tiffsave().
* *
* Returns: 0 on success, -1 on error. * Returns: 0 on success, -1 on error.

View File

@ -645,6 +645,7 @@ write_ppm( Write *write, int ascii )
char *magic; char *magic;
time_t timebuf; time_t timebuf;
magic = "unset";
if( in->BandFmt == VIPS_FORMAT_FLOAT && in->Bands == 3 ) if( in->BandFmt == VIPS_FORMAT_FLOAT && in->Bands == 3 )
magic = "PF"; magic = "PF";
else if( in->BandFmt == VIPS_FORMAT_FLOAT && in->Bands == 1 ) else if( in->BandFmt == VIPS_FORMAT_FLOAT && in->Bands == 1 )

View File

@ -2541,25 +2541,36 @@ vips_class_find( const char *basename, const char *nickname )
return( class ); return( class );
} }
/* What we store for each nickname. We can't just store the type with
* GINT_TO_POINTER() since GType is 64 bits on some platforms.
*/
typedef struct _NicknameGType {
const char *nickname;
GType type;
gboolean duplicate;
} NicknameGType;
static void * static void *
vips_class_add_hash( VipsObjectClass *class, GHashTable *table ) vips_class_add_hash( VipsObjectClass *class, GHashTable *table )
{ {
GType type = G_OBJECT_CLASS_TYPE( class ); GType type = G_OBJECT_CLASS_TYPE( class );
NicknameGType *hit;
/* If this is not a unique name, store -1 for the GType. In this case hit = (NicknameGType *)
g_hash_table_lookup( table, (void *) class->nickname );
/* If this is not a unique name, mark as a duplicate. In this case
* we'll need to fall back to a search. * we'll need to fall back to a search.
*/ */
if( g_hash_table_lookup( table, (void *) class->nickname ) ) { if( hit )
g_hash_table_insert( table, hit->duplicate = TRUE;
(void *) class->nickname, GINT_TO_POINTER( -1 ) ); else {
#ifdef DEBUG hit = g_new( NicknameGType, 1 );
printf( "vips_class_add_hash: duplicate nickname %s\n", hit->nickname = class->nickname;
class->nickname ); hit->type = type;
#endif /*DEBUG*/ hit->duplicate = FALSE;
g_hash_table_insert( table, (void *) hit->nickname, hit );
} }
else
g_hash_table_insert( table,
(void *) class->nickname, GINT_TO_POINTER( type ) );
return( NULL ); return( NULL );
} }
@ -2587,27 +2598,32 @@ vips_type_find( const char *basename, const char *nickname )
const char *classname = basename ? basename : "VipsObject"; const char *classname = basename ? basename : "VipsObject";
NicknameGType *hit;
GType base; GType base;
GType type; GType type;
vips__object_nickname_table = (GHashTable *) g_once( &once, vips__object_nickname_table = (GHashTable *) g_once( &once,
(GThreadFunc) vips_class_build_hash, NULL ); (GThreadFunc) vips_class_build_hash, NULL );
type = GPOINTER_TO_INT( g_hash_table_lookup( hit = (NicknameGType *)
vips__object_nickname_table, (void *) nickname ) ); g_hash_table_lookup( vips__object_nickname_table,
(void *) nickname );
/* We must only search below basename ... check that the cache hit is /* We must only search below basename ... check that the cache hit is
* in the right part of the tree. * in the right part of the tree.
*/ */
if( !(base = g_type_from_name( classname )) ) if( !(base = g_type_from_name( classname )) )
return( 0 ); return( 0 );
if( !type || if( hit &&
type == -1 || !hit->duplicate &&
!g_type_is_a( type, base ) ) { g_type_is_a( hit->type, base ) )
type = hit->type;
else {
VipsObjectClass *class; VipsObjectClass *class;
if( !(class = vips_class_find( basename, nickname )) ) if( !(class = vips_class_find( basename, nickname )) )
return( 0 ); return( 0 );
type = G_OBJECT_CLASS_TYPE( class ); type = G_OBJECT_CLASS_TYPE( class );
} }

View File

@ -953,9 +953,15 @@ vips_call_options_add( VipsObject *object,
GOptionEntry entry[2]; GOptionEntry entry[2];
entry[0].long_name = name; entry[0].long_name = name;
entry[0].short_name = name[0];
entry[0].description = g_param_spec_get_blurb( pspec ); entry[0].description = g_param_spec_get_blurb( pspec );
/* Don't set short names for deprecated args.
*/
if( argument_class->flags & VIPS_ARGUMENT_DEPRECATED )
entry[0].short_name = '\0';
else
entry[0].short_name = name[0];
entry[0].flags = 0; entry[0].flags = 0;
if( !needs_string ) if( !needs_string )
entry[0].flags |= G_OPTION_FLAG_NO_ARG; entry[0].flags |= G_OPTION_FLAG_NO_ARG;

View File

@ -128,6 +128,15 @@ vips_mosaic_build( VipsObject *object )
break; break;
default: default:
/* Silence compiler warnings.
*/
dx0 = 0;
dy0 = 0;
scale1 = 0.0;
angle1 = 0.0;
dx1 = 0.0;
dy1 = 0.0;
g_assert( 0 ); g_assert( 0 );
} }

View File

@ -49,6 +49,8 @@
* 7/3/14 * 7/3/14
* - remove the embedded thumbnail reader, embedded thumbnails are too * - remove the embedded thumbnail reader, embedded thumbnails are too
* unlike the main image wrt. rotation / colour / etc. * unlike the main image wrt. rotation / colour / etc.
* 30/6/14
* - fix interlaced thumbnail output, thanks lovell
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
@ -585,8 +587,10 @@ thumbnail_rotate( VipsObject *process, VipsImage *im )
* (eg.) "/poop/tn_somefile.jpg". * (eg.) "/poop/tn_somefile.jpg".
*/ */
static int static int
thumbnail_write( VipsImage *im, const char *filename ) thumbnail_write( VipsObject *process, VipsImage *im, const char *filename )
{ {
VipsImage **t = (VipsImage **) vips_object_local_array( process, 1 );
char *file; char *file;
char *p; char *p;
char buf[FILENAME_MAX]; char buf[FILENAME_MAX];
@ -618,7 +622,16 @@ thumbnail_write( VipsImage *im, const char *filename )
g_free( file ); g_free( file );
if( vips_image_write_to_file( im, output_name, NULL ) ) { /* We need to cache the whole of the thumbnail before we write it
* in case we are writing an interlaced image. Interlaced png (for
* example) will make 7 passes over the image during write.
*/
if( vips_tilecache( im, &t[0],
"threaded", TRUE,
"persistent", TRUE,
"max_tiles", -1,
NULL ) ||
vips_image_write_to_file( t[0], output_name, NULL ) ) {
g_free( output_name ); g_free( output_name );
return( -1 ); return( -1 );
} }
@ -644,7 +657,7 @@ thumbnail_process( VipsObject *process, const char *filename )
thumbnail_shrink( process, in, interp, sharpen )) || thumbnail_shrink( process, in, interp, sharpen )) ||
!(crop = thumbnail_crop( process, thumbnail )) || !(crop = thumbnail_crop( process, thumbnail )) ||
!(rotate = thumbnail_rotate( process, crop )) || !(rotate = thumbnail_rotate( process, crop )) ||
thumbnail_write( rotate, filename ) ) thumbnail_write( process, rotate, filename ) )
return( -1 ); return( -1 );
return( 0 ); return( 0 );