diff --git a/ChangeLog b/ChangeLog index ba100ac2..9c876550 100644 --- a/ChangeLog +++ b/ChangeLog @@ -20,6 +20,10 @@ - jpeg, png, tiff (though not tiffsave), rad, svg and webp use the new IO class - add @no_strip option to dzsave [kalozka1] +- add iiif layout to dzsave +- fix use of resolution-unit metadata on tiff save [kayarre] + +17/9/19 started 8.8.4 31/8/19 started 8.8.3 - revert sharpen restoring the input colourspace diff --git a/Makefile.am b/Makefile.am index 4b622241..e5f6203c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -14,8 +14,7 @@ EXTRA_DIST = \ autogen.sh \ vips.pc.in \ vips-cpp.pc.in \ - libvips.supp \ - lsan.supp \ + suppressions \ depcomp \ README.md diff --git a/configure.ac b/configure.ac index 5b65c61b..b60c974a 100644 --- a/configure.ac +++ b/configure.ac @@ -788,6 +788,19 @@ if test x"$with_orc" != x"no"; then ) fi +# orc 0.4.30+ works with cf-protection, but 0.4.30 has a bug with multiple +# definitions of OrcTargetPowerPCFlags, so insist on 0.4.31 +if test x"$with_orc" = x"yes"; then + PKG_CHECK_MODULES(ORC_CF_PROTECTION, orc-0.4 >= 0.4.31, + [AC_DEFINE(HAVE_ORC_CF_PROTECTION,1, + [define if your orc works with cf-protection.] + ) + ], + [: + ] + ) +fi + # lcms ... refuse to use lcms1 AC_ARG_WITH([lcms], AS_HELP_STRING([--without-lcms], [build without lcms (default: test)])) @@ -1323,6 +1336,7 @@ AC_OUTPUT([ libvips/Makefile libvips/arithmetic/Makefile libvips/colour/Makefile + libvips/colour/profiles/Makefile libvips/conversion/Makefile libvips/convolution/Makefile libvips/deprecated/Makefile diff --git a/libvips/colour/Makefile.am b/libvips/colour/Makefile.am index 52a4f594..b8ced977 100644 --- a/libvips/colour/Makefile.am +++ b/libvips/colour/Makefile.am @@ -1,5 +1,7 @@ noinst_LTLIBRARIES = libcolour.la +SUBDIRS = profiles + libcolour_la_SOURCES = \ profiles.c \ profiles.h \ @@ -42,7 +44,6 @@ profiles.c: ./wrap-profiles.sh profiles profiles.c EXTRA_DIST = \ - profiles \ wrap-profiles.sh AM_CPPFLAGS = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@ diff --git a/libvips/colour/profiles/Makefile.am b/libvips/colour/profiles/Makefile.am new file mode 100644 index 00000000..fc8f9734 --- /dev/null +++ b/libvips/colour/profiles/Makefile.am @@ -0,0 +1,3 @@ +EXTRA_DIST = \ + cmyk.icm \ + sRGB.icm diff --git a/libvips/foreign/dzsave.c b/libvips/foreign/dzsave.c index 9a9e96b0..6d6ec536 100644 --- a/libvips/foreign/dzsave.c +++ b/libvips/foreign/dzsave.c @@ -83,6 +83,8 @@ * - add @skip_blanks * 21/10/19 * - add @no_strip + * 9/11/19 + * - add IIIF layout */ /* @@ -937,6 +939,103 @@ write_blank( VipsForeignSaveDz *dz ) return( 0 ); } +/* Write IIIF JSON metadata. + */ +static int +write_json( VipsForeignSaveDz *dz ) +{ + /* Can be NULL for memory output. + */ + const char *name = dz->basename ? dz->basename : "untitled"; + + /* dz->file_suffix has a leading "." character. + */ + const char *suffix = dz->file_suffix[0] == '.' ? + dz->file_suffix + 1 : dz->file_suffix; + + GsfOutput *out; + int i; + + out = vips_gsf_path( dz->tree, "info.json", NULL ); + + gsf_output_printf( out, + "{\n" + " \"@context\": \"http://iiif.io/api/image/2/context.json\",\n" + " \"@id\": \"https://example.com/iiif/%s\",\n" + " \"profile\": [\n" + " \"http://iiif.io/api/image/2/level0.json\",\n" + " {\n" + " \"formats\": [\n" + " \"%s\"\n" + " ],\n" + " \"qualities\": [\n" + " \"default\"\n" + " ]\n" + " }\n" + " ],\n" + " \"protocol\": \"http://iiif.io/api/image\",\n", + name, suffix ); + + /* "sizes" is needed for the full/ set of untiled images, which we + * don't yet support. Leave this commented out for now. + + gsf_output_printf( out, + " \"sizes\": [\n" ); + + for( i = 0; i < dz->layer->n + 5; i++ ) { + gsf_output_printf( out, + " {\n" + " \"width\": %d,\n" + " \"height\": \"full\"\n" + " }", + 1 << (i + 4) ); + if( i != dz->layer->n - 4 ) + gsf_output_printf( out, "," ); + gsf_output_printf( out, "\n" ); + } + + gsf_output_printf( out, + " ],\n" ); + + */ + + /* The set of pyramid layers we have written. + */ + gsf_output_printf( out, + " \"tiles\": [\n" + " {\n" + " \"scalefactors\": [\n" ); + + for( i = 0; i < dz->layer->n; i++ ) { + gsf_output_printf( out, + " %d", + 1 << i ); + if( i != dz->layer->n - 1 ) + gsf_output_printf( out, "," ); + gsf_output_printf( out, "\n" ); + } + + gsf_output_printf( out, + " ],\n" + " \"width\": %d\n" + " }\n" + " ],\n", dz->tile_size ); + + gsf_output_printf( out, + " \"width\": %d,\n" + " \"height\": %d\n", + dz->layer->image->Xsize, + dz->layer->image->Ysize ); + + gsf_output_printf( out, + "}\n" ); + + (void) gsf_output_close( out ); + g_object_unref( out ); + + return( 0 ); +} + static int write_vips_meta( VipsForeignSaveDz *dz ) { @@ -1054,7 +1153,6 @@ build_scan_properties( VipsImage *image ) #endif /*HAVE_DATE_TIME_FORMAT_ISO8601*/ vips_dbuf_init( &dbuf ); - vips_dbuf_writef( &dbuf, "\n" ); vips_dbuf_writef( &dbuf, "\n", date ); @@ -1321,6 +1419,40 @@ tile_name( Layer *layer, int x, int y ) break; + case VIPS_FOREIGN_DZ_LAYOUT_IIIF: +{ + /* Tiles are addressed in full resolution coordinates, so + * scale up by layer->sub and dz->tile_size + */ + int left = x * dz->tile_size * layer->sub; + int top = y * dz->tile_size * layer->sub; + int width = VIPS_MIN( dz->tile_size * layer->sub, + layer->width * layer->sub - left ); + int height = VIPS_MIN( dz->tile_size * layer->sub, + layer->height * layer->sub - top ); + + /* IIIF "size" is just real tile width, I think. + * + * TODO .. .is this right? shouldn't it be the smaller of + * width and height? + */ + int size = VIPS_MIN( dz->tile_size, + layer->width - x * dz->tile_size ); + + vips_snprintf( dirname, VIPS_PATH_MAX, "%d,%d,%d,%d", + left, top, width, height ); + vips_snprintf( dirname2, VIPS_PATH_MAX, "%d,", size ); + vips_snprintf( name, VIPS_PATH_MAX, "default%s", + dz->file_suffix ); + + /* "0" is rotation and is always 0. + */ + out = vips_gsf_path( dz->tree, + name, dirname, dirname2, "0", NULL ); +} + + break; + default: g_assert_not_reached(); @@ -1829,10 +1961,11 @@ vips_foreign_save_dz_build( VipsObject *object ) VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( dz ); VipsRect real_pixels; - /* Google and zoomify default to zero overlap, ".jpg". + /* Google, zoomify and iiif default to zero overlap, ".jpg". */ if( dz->layout == VIPS_FOREIGN_DZ_LAYOUT_ZOOMIFY || - dz->layout == VIPS_FOREIGN_DZ_LAYOUT_GOOGLE ) { + dz->layout == VIPS_FOREIGN_DZ_LAYOUT_GOOGLE || + dz->layout == VIPS_FOREIGN_DZ_LAYOUT_IIIF ) { if( !vips_object_argument_isset( object, "overlap" ) ) dz->overlap = 0; if( !vips_object_argument_isset( object, "suffix" ) ) @@ -1847,6 +1980,13 @@ vips_foreign_save_dz_build( VipsObject *object ) dz->tile_size = 256; } + /* Some iif writers default to 256, some to 512. We pick 512. + */ + if( dz->layout == VIPS_FOREIGN_DZ_LAYOUT_IIIF ) { + if( !vips_object_argument_isset( object, "tile_size" ) ) + dz->tile_size = 512; + } + /* skip_blanks defaults to 5 in google mode. */ if( dz->layout == VIPS_FOREIGN_DZ_LAYOUT_GOOGLE && @@ -2151,6 +2291,11 @@ vips_foreign_save_dz_build( VipsObject *object ) return( -1 ); break; + case VIPS_FOREIGN_DZ_LAYOUT_IIIF: + if( write_json( dz ) ) + return( -1 ); + break; + default: g_assert_not_reached(); } diff --git a/libvips/foreign/tiffsave.c b/libvips/foreign/tiffsave.c index cf6ec9bc..5eeb35a2 100644 --- a/libvips/foreign/tiffsave.c +++ b/libvips/foreign/tiffsave.c @@ -159,7 +159,7 @@ vips_foreign_save_tiff_build( VipsObject *object ) /* resunit param overrides resunit metadata. */ - if( vips_object_argument_isset( object, "resunit" ) && + if( !vips_object_argument_isset( object, "resunit" ) && vips_image_get_typeof( save->ready, VIPS_META_RESOLUTION_UNIT ) && !vips_image_get_string( save->ready, diff --git a/libvips/include/vips/foreign.h b/libvips/include/vips/foreign.h index f963fd56..a585a851 100644 --- a/libvips/include/vips/foreign.h +++ b/libvips/include/vips/foreign.h @@ -617,6 +617,7 @@ int vips_niftisave( VipsImage *in, const char *filename, ... ) * @VIPS_FOREIGN_DZ_LAYOUT_DZ: use DeepZoom directory layout * @VIPS_FOREIGN_DZ_LAYOUT_ZOOMIFY: use Zoomify directory layout * @VIPS_FOREIGN_DZ_LAYOUT_GOOGLE: use Google maps directory layout + * @VIPS_FOREIGN_DZ_LAYOUT_IIIF: use IIIF directory layout * * What directory layout and metadata standard to use. */ @@ -624,6 +625,7 @@ typedef enum { VIPS_FOREIGN_DZ_LAYOUT_DZ, VIPS_FOREIGN_DZ_LAYOUT_ZOOMIFY, VIPS_FOREIGN_DZ_LAYOUT_GOOGLE, + VIPS_FOREIGN_DZ_LAYOUT_IIIF, VIPS_FOREIGN_DZ_LAYOUT_LAST } VipsForeignDzLayout; diff --git a/libvips/include/vips/vector.h b/libvips/include/vips/vector.h index 0bbe3504..3752395a 100644 --- a/libvips/include/vips/vector.h +++ b/libvips/include/vips/vector.h @@ -37,15 +37,17 @@ /* If we are building with -fcf-protection (run-time checking of * indirect jumps) then Orc won't work. Make sure it's off. * - * Orc may support -fcf-protection in the future, but does not in June 2019. - * * https://gcc.gnu.org/onlinedocs/gcc/\ * Instrumentation-Options.html#index-fcf-protection * https://gitlab.freedesktop.org/gstreamer/orc/issues/17 + * + * orc 0.4.30 and later work with cf-protection. */ #ifdef __CET__ +#ifndef HAVE_ORC_CF_PROTECTION #undef HAVE_ORC #endif +#endif #ifdef HAVE_ORC #include diff --git a/libvips/iofuncs/enumtypes.c b/libvips/iofuncs/enumtypes.c index a79b0bb8..c22f1ff7 100644 --- a/libvips/iofuncs/enumtypes.c +++ b/libvips/iofuncs/enumtypes.c @@ -612,6 +612,7 @@ vips_foreign_dz_layout_get_type( void ) {VIPS_FOREIGN_DZ_LAYOUT_DZ, "VIPS_FOREIGN_DZ_LAYOUT_DZ", "dz"}, {VIPS_FOREIGN_DZ_LAYOUT_ZOOMIFY, "VIPS_FOREIGN_DZ_LAYOUT_ZOOMIFY", "zoomify"}, {VIPS_FOREIGN_DZ_LAYOUT_GOOGLE, "VIPS_FOREIGN_DZ_LAYOUT_GOOGLE", "google"}, + {VIPS_FOREIGN_DZ_LAYOUT_IIIF, "VIPS_FOREIGN_DZ_LAYOUT_IIIF", "iiif"}, {VIPS_FOREIGN_DZ_LAYOUT_LAST, "VIPS_FOREIGN_DZ_LAYOUT_LAST", "last"}, {0, NULL, NULL} }; diff --git a/libvips/iofuncs/vector.c b/libvips/iofuncs/vector.c index 1595b13d..95b9a8aa 100644 --- a/libvips/iofuncs/vector.c +++ b/libvips/iofuncs/vector.c @@ -54,6 +54,7 @@ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ + #include #include diff --git a/libvips/iofuncs/vips.c b/libvips/iofuncs/vips.c index d3c2df30..26d43687 100644 --- a/libvips/iofuncs/vips.c +++ b/libvips/iofuncs/vips.c @@ -957,8 +957,6 @@ vips__xml_properties( VipsImage *image ) VipsDbuf dbuf; char *date; - vips_dbuf_init( &dbuf ); - #ifdef HAVE_DATE_TIME_FORMAT_ISO8601 { GDateTime *now; @@ -976,6 +974,7 @@ vips__xml_properties( VipsImage *image ) } #endif /*HAVE_DATE_TIME_FORMAT_ISO8601*/ + vips_dbuf_init( &dbuf ); vips_dbuf_writef( &dbuf, "\n" ); vips_dbuf_writef( &dbuf, "\n", diff --git a/test/test_formats.sh b/test/test_formats.sh index 830f0e3f..96992123 100755 --- a/test/test_formats.sh +++ b/test/test_formats.sh @@ -12,10 +12,6 @@ set -e poppler=$test_images/blankpage.pdf poppler_ref=$test_images/blankpage.pdf.png -# rsvg / svgload reference image -rsvg=$test_images/blankpage.svg -rsvg_ref=$test_images/blankpage.svg.png - # giflib / gifload reference image giflib=$test_images/trans-x.gif giflib_ref=$test_images/trans-x.png @@ -220,10 +216,7 @@ if test_supported pdfload; then test_loader $poppler_ref $poppler pdfload 0 fi -if test_supported svgload; then - # librsvg can give small differences on some platforms - test_loader $rsvg_ref $rsvg svgload 10 -fi +# don't test SVG --- the output varies too much between librsvg versions if test_supported gifload; then test_loader $giflib_ref $giflib gifload 0