diff --git a/ChangeLog b/ChangeLog index b4b0d9a1..9c805abc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,18 @@ +<<<<<<< HEAD 26/6/14 started 7.40.2 - 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 - revise man.1 pages diff --git a/Makefile.am b/Makefile.am index 583d7bb1..6dc8431b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,6 +19,14 @@ P_COMPILE_DIR = P_DIST_DIR = swig endif +if ENABLE_DOCS +D_DIST_DIR = +D_BUILD_DIR = doc +else +D_DIST_DIR = doc +D_BUILD_DIR = +endif + SUBDIRS = \ libvips \ tools \ @@ -26,7 +34,8 @@ SUBDIRS = \ man \ doc \ $(C_COMPILE_DIR) \ - $(P_COMPILE_DIR) + $(P_COMPILE_DIR) \ + $(D_BUILD_DIR) EXTRA_DIST = \ m4 \ @@ -38,15 +47,18 @@ EXTRA_DIST = \ acinclude.m4 \ depcomp \ $(C_DIST_DIR) \ - $(P_DIST_DIR) + $(P_DIST_DIR) \ + $(D_DIST_DIR) pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = vips.pc $(C_PKGCONFIG) +if ENABLE_DOCS install-exec-hook: -rm -rf ${DESTDIR}$(datadir)/doc/vips $(mkinstalldirs) ${DESTDIR}$(datadir)/doc/vips -cp -r ${top_srcdir}/doc/html ${top_srcdir}/doc/pdf ${DESTDIR}$(datadir)/doc/vips +endif dist-hook: # make sure we don't get any .svn dirs from EXTRA_DIST diff --git a/README.md b/README.md index 8f49da41..c7388724 100644 --- a/README.md +++ b/README.md @@ -109,8 +109,9 @@ Static analysis with: # Dependencies -libvips has to have gettext, glib-2.x and libxml-2.0. The build system needs -sh, pkg-config, swig, gtk-doc-tools, automake, gobject-introspection and gnu make. +libvips has to have gettext, glib-2.x and libxml-2.0. The build system +needs sh, pkg-config, swig, gtk-doc-tools, automake, gobject-introspection +and gnu make. # 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 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 If libvips finds this library, it uses it for fourier transforms. It diff --git a/TODO b/TODO index a8297c31..0475cf41 100644 --- a/TODO +++ b/TODO @@ -14,6 +14,8 @@ gtk-doc now used markdown, phew, use this to expand some sections + + - can we use postbuild elsewhere? look at use of "preclose" / "written", etc. @@ -36,7 +38,9 @@ - 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? diff --git a/configure.ac b/configure.ac index 5e7a3e5c..6921a4ae 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # 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 AC_PREREQ(2.62) @@ -18,7 +18,7 @@ AC_CONFIG_MACRO_DIR([m4]) # user-visible library versioning m4_define([vips_major_version], [7]) m4_define([vips_minor_version], [40]) -m4_define([vips_micro_version], [2]) +m4_define([vips_micro_version], [3]) m4_define([vips_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 not backwards compatible?: reset age to 0 -LIBRARY_CURRENT=37 -LIBRARY_REVISION=5 +LIBRARY_CURRENT=38 +LIBRARY_REVISION=1 LIBRARY_AGE=0 # patched into include/vips/version.h @@ -124,6 +124,23 @@ else 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]) case "$host" in *-*-mingw*) @@ -190,6 +207,20 @@ else fi 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 AC_SYS_LARGEFILE @@ -233,7 +264,9 @@ if test x"$enable_cxx" != x"no"; then # need -lstdc++ for (eg.) the C++ format loaders # this gets added to vips.pc to help mingw and friends link programs # using libvips - VIPS_CXX_LIBS="-lstdc++" + if test x"$vips_needs_stdcpp" != x"no"; then + VIPS_CXX_LIBS="-lstdc++" + fi enable_cxx=yes 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,[ 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 build C++ components: $enable_cxx build docs with gtkdoc: $enable_gtk_doc +install docs: $enable_docs gobject introspection: $found_introspection * optional packages and modules diff --git a/libvips/convolution/compass.c b/libvips/convolution/compass.c index 9a173834..74e64c38 100644 --- a/libvips/convolution/compass.c +++ b/libvips/convolution/compass.c @@ -123,6 +123,9 @@ vips_compass_build( VipsObject *object ) break; default: + /* Silence compiler wrning. + */ + x = NULL; g_assert( 0 ); } diff --git a/libvips/foreign/dzsave.c b/libvips/foreign/dzsave.c index a322b92b..a10fb8b8 100644 --- a/libvips/foreign/dzsave.c +++ b/libvips/foreign/dzsave.c @@ -43,7 +43,8 @@ * - set Type on strips so we can convert for save correctly, thanks * philipgiuliani * 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 */ @@ -166,6 +167,7 @@ typedef struct _VipsGsfDirectory { * this on cleanup. */ GsfOutput *container; + } VipsGsfDirectory; /* Close all dirs, non-NULL on error. @@ -389,6 +391,7 @@ struct _VipsForeignSaveDz { VipsArrayDouble *background; VipsForeignDzDepth depth; gboolean centre; + gboolean properties; VipsAngle angle; VipsForeignDzContainer container; @@ -420,6 +423,11 @@ struct _VipsForeignSaveDz { * becomes ".jpg". */ 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; @@ -706,8 +714,10 @@ write_vips_property( VipsImage *image, char *str_value; str_value = g_strdup_value_contents( value ); - gsf_output_printf( out, " %s\n", field ); - gsf_output_printf( out, " %s\n", str_value ); + gsf_output_printf( out, " \n" ); + gsf_output_printf( out, " %s\n", field ); + gsf_output_printf( out, " %s\n", str_value ); + gsf_output_printf( out, " \n" ); g_free( str_value ); return( NULL ); @@ -718,14 +728,26 @@ write_vips_properties( VipsForeignSaveDz *dz ) { VipsForeignSave *save = (VipsForeignSave *) dz; + time_t now; + char time_string[50]; GsfOutput *out; + time( &now ); + strftime( time_string, sizeof( time_string ), + "%FT%TZ", gmtime( &now ) ); + out = vips_gsf_path( dz->tree, "vips-properties.xml", dz->root_name, NULL ); gsf_output_printf( out, "\n" ); - gsf_output_printf( out, "\n" ); + gsf_output_printf( out, "\n" ); gsf_output_printf( out, " \n" ); (void) vips_image_map( save->ready, write_vips_property, out ); gsf_output_printf( out, " \n" ); @@ -1039,12 +1061,14 @@ strip_work( VipsThreadState *state, void *a ) Strip *strip = (Strip *) a; Layer *layer = strip->layer; VipsForeignSaveDz *dz = layer->dz; + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( dz ); VipsImage *x; VipsImage *t; void *buf; size_t len; GsfOutput *out; + gboolean status; #ifdef DEBUG_VERBOSE printf( "strip_work\n" ); @@ -1115,14 +1139,37 @@ strip_work( VipsThreadState *state, void *a ) out = tile_name( layer, 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 ); g_object_unref( out ); - g_mutex_unlock( vips__global_lock ); - g_free( buf ); + if( !status ) { + g_mutex_unlock( vips__global_lock ); + + 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 printf( "strip_work: success\n" ); #endif /*DEBUG_VERBOSE*/ @@ -1406,7 +1453,7 @@ pyramid_strip( VipsRegion *region, VipsRect *area, void *a ) */ if( layer->write_y == VIPS_RECT_BOTTOM( to ) || layer->write_y == layer->height ) { - if( strip_arrived( layer ) ) + if( strip_arrived( layer ) ) return( -1 ); } } @@ -1666,7 +1713,8 @@ vips_foreign_save_dz_build( VipsObject *object ) return( -1 ); } - if( write_vips_properties( dz ) ) + if( dz->properties && + write_vips_properties( dz ) ) return( -1 ); 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_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. */ @@ -1886,16 +1941,17 @@ vips_foreign_save_dz_init( VipsForeignSaveDz *dz ) * @centre: centre the tiles * @angle: rotate the image by this much * @container: set container type + * @properties: write a properties file * * Save an image as a set of tiles at various resolutions. By default dzsave * uses DeepZoom layout -- use @layout to pick other conventions. * * 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. * - * You can set @suffix to something like ".jpg[Q=85]" to control the tile write - * options. + * You can set @suffix to something like `".jpg[Q=85]"` to control the tile + * write options. * * 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 @@ -1908,6 +1964,12 @@ vips_foreign_save_dz_init( VipsForeignSaveDz *dz ) * Use @depth to control how low the pyramid goes. This defaults to the * 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(). * * Returns: 0 on success, -1 on error. diff --git a/libvips/foreign/ppm.c b/libvips/foreign/ppm.c index c3ed3073..16ef125a 100644 --- a/libvips/foreign/ppm.c +++ b/libvips/foreign/ppm.c @@ -645,6 +645,7 @@ write_ppm( Write *write, int ascii ) char *magic; time_t timebuf; + magic = "unset"; if( in->BandFmt == VIPS_FORMAT_FLOAT && in->Bands == 3 ) magic = "PF"; else if( in->BandFmt == VIPS_FORMAT_FLOAT && in->Bands == 1 ) diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index 00fdc59a..abbff396 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -2541,25 +2541,36 @@ vips_class_find( const char *basename, const char *nickname ) 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 * vips_class_add_hash( VipsObjectClass *class, GHashTable *table ) { 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. */ - if( g_hash_table_lookup( table, (void *) class->nickname ) ) { - g_hash_table_insert( table, - (void *) class->nickname, GINT_TO_POINTER( -1 ) ); -#ifdef DEBUG - printf( "vips_class_add_hash: duplicate nickname %s\n", - class->nickname ); -#endif /*DEBUG*/ + if( hit ) + hit->duplicate = TRUE; + else { + hit = g_new( NicknameGType, 1 ); + hit->nickname = class->nickname; + hit->type = type; + 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 ); } @@ -2587,27 +2598,32 @@ vips_type_find( const char *basename, const char *nickname ) const char *classname = basename ? basename : "VipsObject"; + NicknameGType *hit; GType base; GType type; vips__object_nickname_table = (GHashTable *) g_once( &once, (GThreadFunc) vips_class_build_hash, NULL ); - type = GPOINTER_TO_INT( g_hash_table_lookup( - vips__object_nickname_table, (void *) nickname ) ); + hit = (NicknameGType *) + g_hash_table_lookup( vips__object_nickname_table, + (void *) nickname ); /* We must only search below basename ... check that the cache hit is * in the right part of the tree. */ if( !(base = g_type_from_name( classname )) ) return( 0 ); - if( !type || - type == -1 || - !g_type_is_a( type, base ) ) { + if( hit && + !hit->duplicate && + g_type_is_a( hit->type, base ) ) + type = hit->type; + else { VipsObjectClass *class; if( !(class = vips_class_find( basename, nickname )) ) return( 0 ); + type = G_OBJECT_CLASS_TYPE( class ); } diff --git a/libvips/iofuncs/operation.c b/libvips/iofuncs/operation.c index 716e1b38..738829a4 100644 --- a/libvips/iofuncs/operation.c +++ b/libvips/iofuncs/operation.c @@ -953,9 +953,15 @@ vips_call_options_add( VipsObject *object, GOptionEntry entry[2]; entry[0].long_name = name; - entry[0].short_name = name[0]; 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; if( !needs_string ) entry[0].flags |= G_OPTION_FLAG_NO_ARG; diff --git a/libvips/mosaicing/mosaic.c b/libvips/mosaicing/mosaic.c index 8454589a..f630dd0a 100644 --- a/libvips/mosaicing/mosaic.c +++ b/libvips/mosaicing/mosaic.c @@ -128,6 +128,15 @@ vips_mosaic_build( VipsObject *object ) break; default: + /* Silence compiler warnings. + */ + dx0 = 0; + dy0 = 0; + scale1 = 0.0; + angle1 = 0.0; + dx1 = 0.0; + dy1 = 0.0; + g_assert( 0 ); } diff --git a/tools/vipsthumbnail.c b/tools/vipsthumbnail.c index c242942c..ab411e7d 100644 --- a/tools/vipsthumbnail.c +++ b/tools/vipsthumbnail.c @@ -49,6 +49,8 @@ * 7/3/14 * - remove the embedded thumbnail reader, embedded thumbnails are too * unlike the main image wrt. rotation / colour / etc. + * 30/6/14 + * - fix interlaced thumbnail output, thanks lovell */ #ifdef HAVE_CONFIG_H @@ -585,8 +587,10 @@ thumbnail_rotate( VipsObject *process, VipsImage *im ) * (eg.) "/poop/tn_somefile.jpg". */ 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 *p; char buf[FILENAME_MAX]; @@ -618,7 +622,16 @@ thumbnail_write( VipsImage *im, const char *filename ) 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 ); return( -1 ); } @@ -644,7 +657,7 @@ thumbnail_process( VipsObject *process, const char *filename ) thumbnail_shrink( process, in, interp, sharpen )) || !(crop = thumbnail_crop( process, thumbnail )) || !(rotate = thumbnail_rotate( process, crop )) || - thumbnail_write( rotate, filename ) ) + thumbnail_write( process, rotate, filename ) ) return( -1 ); return( 0 );