diff --git a/configure.ac b/configure.ac index d7293543..0a199762 100644 --- a/configure.ac +++ b/configure.ac @@ -627,6 +627,29 @@ if test x"$with_rsvg" != x"no"; then ) fi +# zlib +# some platforms, like macosx, are missing the .pc files for zlib, so +# we fall back to FIND_ZLIB +AC_ARG_WITH([zlib], + AS_HELP_STRING([--without-zlib], [build without zlib (default: test)])) + +if test x"$with_zlib" != "xno"; then + PKG_CHECK_MODULES(ZLIB, zlib >= 0.4, + [AC_DEFINE(HAVE_ZLIB,1,[define if you have zlib installed.]) + with_zlib=yes + PACKAGES_USED="$PACKAGES_USED zlib" + ], + [FIND_ZLIB( + [with_zlib="yes (found by search)" + ], + [AC_MSG_WARN([zlib not found; disabling SVGZ buffer support]) + with_zlib=no + ] + ) + ] + ) +fi + # OpenSlide AC_ARG_WITH([openslide], AS_HELP_STRING([--without-openslide], @@ -787,15 +810,6 @@ fi AM_CONDITIONAL(ENABLE_PYVIPS8, test x"$enable_pyvips8" = x"yes") -# hmm, these don't have .pc files on ubuntu 5.10, how odd -FIND_ZIP( - [with_zip=yes - ], - [AC_MSG_WARN([libz not found; disabling ZIP support]) - with_zip=no - ] -) - # look for TIFF with pkg-config ... fall back to our tester # pkgconfig support for libtiff starts with libtiff-4 AC_ARG_WITH([tiff], @@ -944,14 +958,14 @@ fi # Gather all up for VIPS_CFLAGS, VIPS_INCLUDES, VIPS_LIBS # sort includes to get longer, more specific dirs first # helps, for example, selecting graphicsmagick over imagemagick -VIPS_CFLAGS=`for i in $VIPS_CFLAGS $GTHREAD_CFLAGS $REQUIRED_CFLAGS $PANGOFT2_CFLAGS $GSF_CFLAGS $FFTW_CFLAGS $MAGICK_CFLAGS $PNG_CFLAGS $EXIF_CFLAGS $MATIO_CFLAGS $CFITSIO_CFLAGS $LIBWEBP_CFLAGS $GIFLIB_INCLUDES $RSVG_CFLAGS $POPPLER_CFLAGS $OPENEXR_CFLAGS $OPENSLIDE_CFLAGS $ORC_CFLAGS $TIFF_CFLAGS $LCMS_CFLAGS +VIPS_CFLAGS=`for i in $VIPS_CFLAGS $GTHREAD_CFLAGS $REQUIRED_CFLAGS $ZLIB_CFLAGS $PANGOFT2_CFLAGS $GSF_CFLAGS $FFTW_CFLAGS $MAGICK_CFLAGS $PNG_CFLAGS $EXIF_CFLAGS $MATIO_CFLAGS $CFITSIO_CFLAGS $LIBWEBP_CFLAGS $GIFLIB_INCLUDES $RSVG_CFLAGS $POPPLER_CFLAGS $OPENEXR_CFLAGS $OPENSLIDE_CFLAGS $ORC_CFLAGS $TIFF_CFLAGS $LCMS_CFLAGS do echo $i done | sort -ru` VIPS_CFLAGS=`echo $VIPS_CFLAGS` VIPS_CFLAGS="$VIPS_DEBUG_FLAGS $VIPS_CFLAGS" -VIPS_INCLUDES="$PNG_INCLUDES $TIFF_INCLUDES $ZIP_INCLUDES $JPEG_INCLUDES" -VIPS_LIBS="$MAGICK_LIBS $PNG_LIBS $TIFF_LIBS $ZIP_LIBS $JPEG_LIBS $GTHREAD_LIBS $REQUIRED_LIBS $PANGOFT2_LIBS $GSF_LIBS $FFTW_LIBS $ORC_LIBS $LCMS_LIBS $GIFLIB_LIBS $RSVG_LIBS $POPPLER_LIBS $OPENEXR_LIBS $OPENSLIDE_LIBS $CFITSIO_LIBS $LIBWEBP_LIBS $MATIO_LIBS $EXIF_LIBS -lm" +VIPS_INCLUDES="$ZLIB_INCLUDES $PNG_INCLUDES $TIFF_INCLUDES $JPEG_INCLUDES" +VIPS_LIBS="$ZLIB_LIBS $MAGICK_LIBS $PNG_LIBS $TIFF_LIBS $JPEG_LIBS $GTHREAD_LIBS $REQUIRED_LIBS $PANGOFT2_LIBS $GSF_LIBS $FFTW_LIBS $ORC_LIBS $LCMS_LIBS $GIFLIB_LIBS $RSVG_LIBS $POPPLER_LIBS $OPENEXR_LIBS $OPENSLIDE_LIBS $CFITSIO_LIBS $LIBWEBP_LIBS $MATIO_LIBS $EXIF_LIBS -lm" AC_SUBST(VIPS_LIBDIR) diff --git a/libvips/foreign/svgload.c b/libvips/foreign/svgload.c index 9bae681a..a0d1606a 100644 --- a/libvips/foreign/svgload.c +++ b/libvips/foreign/svgload.c @@ -54,6 +54,16 @@ #include #include +/* Old librsvg versions don't include librsvg-features.h by default, + * while newer versions deprecate direct inclusion. + */ +#ifndef LIBRSVG_FEATURES_H +#include +#endif + +#if LIBRSVG_CHECK_FEATURE(SVGZ) && defined(HAVE_ZLIB) +#include +#endif typedef struct _VipsForeignLoadSvg { VipsForeignLoad parent_object; @@ -315,6 +325,9 @@ vips_foreign_load_svg_file_header( VipsForeignLoad *load ) static const char *vips_foreign_svg_suffs[] = { ".svg", +#if LIBRSVG_CHECK_FEATURE(SVGZ) + ".svgz", +#endif NULL }; @@ -364,13 +377,66 @@ typedef VipsForeignLoadSvgClass VipsForeignLoadSvgBufferClass; G_DEFINE_TYPE( VipsForeignLoadSvgBuffer, vips_foreign_load_svg_buffer, vips_foreign_load_svg_get_type() ); +#if LIBRSVG_CHECK_FEATURE(SVGZ) && defined(HAVE_ZLIB) +static void * +vips_zalloc( void *opaque, unsigned items, unsigned size ) +{ + return( g_malloc0_n( items, size ) ); +} + +static void +vips_zfree( void *opaque, void *ptr ) +{ + return( g_free( ptr ) ); +} +#endif + static gboolean vips_foreign_load_svg_is_a_buffer( const void *buf, size_t len ) { - char *str = (char *) buf; + unsigned char *str = (unsigned char *) buf; int i; +#if LIBRSVG_CHECK_FEATURE(SVGZ) && defined(HAVE_ZLIB) + /* Check for SVGZ gzip signature and inflate. + * Minimum gzip size is 18 bytes, starting with 1F 8B. + */ + if( len >= 18 && str[0] == 0x1f && str[1] == 0x8b ) { + z_stream zs; + size_t opos = 0; + unsigned char obuf[224]; + + zs.zalloc = (alloc_func) vips_zalloc; + zs.zfree = (free_func) vips_zfree; + zs.opaque = Z_NULL; + zs.next_in = str; + zs.avail_in = len; + + if( inflateInit2(&zs, 15 | 32) != Z_OK ) { + vips_error( "svgload", + "%s", _( "Zlib init failed" ) ); + return( -1 ); + } + + do { + zs.avail_out = sizeof(obuf) - opos; + zs.next_out = obuf + opos; + if( inflate(&zs, Z_NO_FLUSH) < Z_OK ) { + vips_error( "svgload", + "%s", _( "Zlib inflate failed" ) ); + return( -1 ); + } + opos = sizeof(obuf) - zs.avail_out; + } while( opos < sizeof(obuf) && zs.avail_out == 0 ); + + inflateEnd(&zs); + + str = obuf; + len = opos; + } +#endif + /* SVG documents are very freeform. They normally look like: * * @@ -390,15 +456,10 @@ vips_foreign_load_svg_is_a_buffer( const void *buf, size_t len ) return( 0 ); for( i = 0; i < 24; i++ ) if( !isascii( str[i] ) ) - return( 0 ); + return( 0 ); for( i = 0; i < 200 && i < len - 5; i++ ) { - char txt[5]; - - /* 5, since we include the \0 at the end. - */ - vips_strncpy( txt, buf + i, 5 ); - if( strcasecmp( txt, "],[int a;],[ - ZIP_INCLUDES="" - ], [ - # zlib.h is not in the standard search path, try - # $prefix - zip_save_INCLUDES="$INCLUDES" - - INCLUDES="-I${prefix}/include $INCLUDES" - - AC_TRY_COMPILE([#include ],[int a;],[ - ZIP_INCLUDES="-I${prefix}/include" - ], [ - ZIP_INCLUDES="no" - ]) - - INCLUDES=$zip_save_INCLUDES - ]) -fi - -# Now for the libraries -if test "$ZIP_LIBS" = ""; then - zip_save_LIBS="$LIBS" - zip_save_INCLUDES="$INCLUDES" - - LIBS="-lz $LIBS" - INCLUDES="$ZIP_INCLUDES $INCLUDES" - - # Try the standard search path first - AC_TRY_LINK([#include ],[zlibVersion()], [ - ZIP_LIBS="-lz" - ], [ - # libz is not in the standard search path, try $prefix - - LIBS="-L${prefix}/lib $LIBS" - - AC_TRY_LINK([#include ],[zlibVersion()], [ - ZIP_LIBS="-L${prefix}/lib -lz" - ], [ - ZIP_LIBS=no - ]) - ]) - - LIBS="$zip_save_LIBS" - INCLUDES="$zip_save_INCLUDES" -fi - -AC_SUBST(ZIP_LIBS) -AC_SUBST(ZIP_INCLUDES) - -# Print a helpful message -zip_libraries_result="$ZIP_LIBS" -zip_includes_result="$ZIP_INCLUDES" - -if test x"$zip_libraries_result" = x""; then - zip_libraries_result="in default path" -fi -if test x"$zip_includes_result" = x""; then - zip_includes_result="in default path" -fi - -if test "$zip_libraries_result" = "no"; then - zip_libraries_result="(none)" -fi -if test "$zip_includes_result" = "no"; then - zip_includes_result="(none)" -fi - -AC_MSG_RESULT([libraries $zip_libraries_result, headers $zip_includes_result]) - -# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test "$ZIP_INCLUDES" != "no" && test "$ZIP_LIBS" != "no"; then - AC_DEFINE(HAVE_ZIP,1,[Define if you have libz libraries and header files.]) - $1 -else - ZIP_LIBS="" - ZIP_INCLUDES="" - $2 -fi - -])dnl diff --git a/m4/zlib.m4 b/m4/zlib.m4 new file mode 100644 index 00000000..eaeb1c39 --- /dev/null +++ b/m4/zlib.m4 @@ -0,0 +1,124 @@ +dnl From FIND_MOTIF and ACX_PTHREAD, without much understanding +dnl +dnl FIND_ZLIB[ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]] +dnl ------------------------------------------------ +dnl +dnl Find zlib libraries and headers ... useful for platforms which are missing +dnl the zlib .pc file +dnl +dnl Put compile stuff in ZLIB_INCLUDES +dnl Put link stuff in ZLIB_LIBS +dnl Define HAVE_ZLIB if found +dnl +AC_DEFUN([FIND_ZLIB], [ +AC_REQUIRE([AC_PATH_XTRA]) + +ZLIB_INCLUDES="" +ZLIB_LIBS="" + +AC_ARG_WITH(zlib, + AS_HELP_STRING([--without-zlib], [build without zlib (default: test)])) +# Treat --without-zlib like --without-zlib-includes --without-zlib-libraries. +if test "$with_zlib" = "no"; then + ZLIB_INCLUDES=no + ZLIB_LIBS=no +fi + +AC_ARG_WITH(zlib-includes, + AS_HELP_STRING([--with-zlib-includes=DIR], [libz includes are in DIR]), + ZLIB_INCLUDES="-I$withval") +AC_ARG_WITH(zlib-libraries, + AS_HELP_STRING([--with-zlib-libraries=DIR], [libz libraries are in DIR]), + ZLIB_LIBS="-L$withval -lz") + +AC_MSG_CHECKING(for ZLIB) + +# Look for zlib.h +if test "$ZLIB_INCLUDES" = ""; then + # Check the standard search path + AC_TRY_COMPILE([#include + #include ],[int a;],[ + ZLIB_INCLUDES="" + ], [ + # zlib.h is not in the standard search path, try + # $prefix + zlib_save_INCLUDES="$INCLUDES" + + INCLUDES="-I${prefix}/include $INCLUDES" + + AC_TRY_COMPILE([#include + #include ],[int a;],[ + ZLIB_INCLUDES="-I${prefix}/include" + ], [ + ZLIB_INCLUDES="no" + ]) + + INCLUDES=$zlib_save_INCLUDES + ]) +fi + +# Now for the libraries +if test "$ZLIB_LIBS" = ""; then + zlib_save_LIBS="$LIBS" + zlib_save_INCLUDES="$INCLUDES" + + LIBS="-lz $LIBS" + INCLUDES="$ZLIB_INCLUDES $INCLUDES" + + # Try the standard search path first + AC_TRY_LINK([#include + #include + ],[z_stream zs;inflateInit2(&zs, 15 | 32)], [ + ZLIB_LIBS="-lz" + ], [ + # libz is not in the standard search path, try $prefix + + LIBS="-L${prefix}/lib $LIBS" + + AC_TRY_LINK([#include + #include + ],[z_stream zs;inflateInit2(&zs, 15 | 32)], [ + ZLIB_LIBS="-L${prefix}/lib -lz" + ], [ + ZLIB_LIBS=no + ]) + ]) + + LIBS="$zlib_save_LIBS" + INCLUDES="$zlib_save_INCLUDES" +fi + +AC_SUBST(ZLIB_LIBS) +AC_SUBST(ZLIB_INCLUDES) + +# Print a helpful message +zlib_libraries_result="$ZLIB_LIBS" +zlib_includes_result="$ZLIB_INCLUDES" + +if test x"$zlib_libraries_result" = x""; then + zlib_libraries_result="in default path" +fi +if test x"$zlib_includes_result" = x""; then + zlib_includes_result="in default path" +fi + +if test "$zlib_libraries_result" = "no"; then + zlib_libraries_result="(none)" +fi +if test "$zlib_includes_result" = "no"; then + zlib_includes_result="(none)" +fi + +AC_MSG_RESULT([libraries $zlib_libraries_result, headers $zlib_includes_result]) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test "$ZLIB_INCLUDES" != "no" && test "$ZLIB_LIBS" != "no"; then + AC_DEFINE(HAVE_ZLIB,1,[Define if you have zlib libraries and header files.]) + $1 +else + ZLIB_INCLUDES="" + ZLIB_LIBS="" + $2 +fi + +])dnl diff --git a/test/images/vips-profile.svgz b/test/images/vips-profile.svgz new file mode 100644 index 00000000..8ccb610f Binary files /dev/null and b/test/images/vips-profile.svgz differ diff --git a/test/test_foreign.py b/test/test_foreign.py index 06cd84e6..80a84d8d 100755 --- a/test/test_foreign.py +++ b/test/test_foreign.py @@ -50,6 +50,7 @@ class TestForeign(unittest.TestCase): self.pdf_file = "images/ISO_12233-reschart.pdf" self.cmyk_pdf_file = "images/cmyktest.pdf" self.svg_file = "images/vips-profile.svg" + self.svgz_file = "images/vips-profile.svgz" self.colour = Vips.Image.jpegload(self.jpeg_file) self.mono = self.colour.extract_band(1) @@ -497,6 +498,9 @@ class TestForeign(unittest.TestCase): self.file_loader("svgload", self.svg_file, svg_valid) self.buffer_loader("svgload_buffer", self.svg_file, svg_valid) + self.file_loader("svgload", self.svgz_file, svg_valid) + self.buffer_loader("svgload_buffer", self.svgz_file, svg_valid) + im = Vips.Image.new_from_file(self.svg_file) x = Vips.Image.new_from_file(self.svg_file, scale = 2) self.assertLess(abs(im.width * 2 - x.width), 2)