diff --git a/ChangeLog b/ChangeLog index e7eff003..bcf482d8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,9 @@ - update libtool support in configure.ac - more startup info if VIPS_INFO is set - command-line programs set glib prgname (no longer set for you by VIPS_INIT) +- enable strip chopping for TIFF read [DavidStorm] +- disable modules by default for static builds [kleisauke] +- fix jpeg tiff pyramid save 14/8/20 started 8.11 - add vips_jpegload_source() and vips_svgload_source() to public C API diff --git a/configure.ac b/configure.ac index e610f0ed..356293b7 100644 --- a/configure.ac +++ b/configure.ac @@ -423,8 +423,15 @@ PKG_CHECK_MODULES(HAVE_CHECKED_MUL, glib-2.0 >= 2.48, AC_MSG_CHECKING([whether to build dynamic modules]) +# Disable modules by default when building static libraries +AS_IF([test x"$enable_static" = x"yes"], + [enable_modules_default=no], + [enable_modules_default=yes]) + AC_ARG_ENABLE([modules], - AS_HELP_STRING([--disable-modules], [disable dynamic modules (default: enabled)])) + AS_HELP_STRING([--disable-modules], [disable dynamic modules (default: test)]), + [enable_modules="$enableval"], + [enable_modules="$enable_modules_default"]) gmodule_supported_bool=false gmodule_supported_flag=no diff --git a/libvips/foreign/svgload.c b/libvips/foreign/svgload.c index 0974f79d..fa89874b 100644 --- a/libvips/foreign/svgload.c +++ b/libvips/foreign/svgload.c @@ -245,9 +245,11 @@ vips_foreign_load_svg_get_flags( VipsForeignLoad *load ) return( VIPS_FOREIGN_SEQUENTIAL ); } -static void +static int vips_foreign_load_svg_parse( VipsForeignLoadSvg *svg, VipsImage *out ) { + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( svg ); + RsvgDimensionData dimensions; int width; int height; @@ -261,6 +263,11 @@ vips_foreign_load_svg_parse( VipsForeignLoadSvg *svg, VipsImage *out ) width = dimensions.width; height = dimensions.height; + if( width <= 0 || height <= 0 ) { + vips_error( class->nickname, "%s", _( "bad dimensions" ) ); + return( -1 ); + } + /* Calculate dimensions at required dpi/scale. */ scale = svg->scale * svg->dpi / 72.0; @@ -300,6 +307,7 @@ vips_foreign_load_svg_parse( VipsForeignLoadSvg *svg, VipsImage *out ) */ vips_image_pipelinev( out, VIPS_DEMAND_STYLE_FATSTRIP, NULL ); + return( 0 ); } static int @@ -307,9 +315,7 @@ vips_foreign_load_svg_header( VipsForeignLoad *load ) { VipsForeignLoadSvg *svg = (VipsForeignLoadSvg *) load; - vips_foreign_load_svg_parse( svg, load->out ); - - return( 0 ); + return vips_foreign_load_svg_parse( svg, load->out ); } static int @@ -386,9 +392,9 @@ vips_foreign_load_svg_load( VipsForeignLoad *load ) * Make tiles 2000 pixels high to limit overcomputation. */ t[0] = vips_image_new(); - vips_foreign_load_svg_parse( svg, t[0] ); - if( vips_image_generate( t[0], - NULL, vips_foreign_load_svg_generate, NULL, svg, NULL ) || + if( vips_foreign_load_svg_parse( svg, t[0] ) || + vips_image_generate( t[0], NULL, + vips_foreign_load_svg_generate, NULL, svg, NULL ) || vips_tilecache( t[0], &t[1], "tile_width", VIPS_MIN( t[0]->Xsize, RSVG_MAX_WIDTH ), "tile_height", 2000, diff --git a/libvips/foreign/tiff.c b/libvips/foreign/tiff.c index 744ac6d3..5299ef51 100644 --- a/libvips/foreign/tiff.c +++ b/libvips/foreign/tiff.c @@ -212,7 +212,14 @@ vips__tiff_openin_source( VipsSource *source ) if( vips_source_rewind( source ) ) return( NULL ); - if( !(tiff = TIFFClientOpen( "source input", "rm", + /* Disable memory mapped input -- it chews up VM and the performance + * gain is very small. + * + * C enables strip chopping: very large uncompressed strips are + * chopped into c. 8kb chunks. This can reduce peak memory use for + * this type of file. + */ + if( !(tiff = TIFFClientOpen( "source input", "rmC", (thandle_t) source, openin_source_read, openin_source_write, diff --git a/libvips/foreign/tiff2vips.c b/libvips/foreign/tiff2vips.c index 9c186866..d356872e 100644 --- a/libvips/foreign/tiff2vips.c +++ b/libvips/foreign/tiff2vips.c @@ -327,7 +327,7 @@ typedef struct _RtiffHeader { */ double stonits; - /* Number of subifds, if any. + /* Number of subifds, 0 for none. */ int subifd_count; @@ -684,7 +684,7 @@ rtiff_set_page( Rtiff *rtiff, int page ) } if( rtiff->subifd >= 0 ) { - int subifd_count; + uint16 subifd_count; toff_t *subifd_offsets; if( !TIFFGetField( rtiff->tiff, TIFFTAG_SUBIFD, @@ -694,8 +694,7 @@ rtiff_set_page( Rtiff *rtiff, int page ) return( -1 ); } - if( subifd_count <= 0 || - rtiff->subifd >= subifd_count ) { + if( rtiff->subifd >= subifd_count ) { vips_error( "tiff2vips", _( "subifd %d out of range, " "only 0-%d available" ), @@ -2437,6 +2436,7 @@ rtiff_header_read( Rtiff *rtiff, RtiffHeader *header ) int i; uint16 extra_samples_count; uint16 *extra_samples_types; + uint16 subifd_count; toff_t *subifd_offsets; char *image_description; @@ -2545,10 +2545,11 @@ rtiff_header_read( Rtiff *rtiff, RtiffHeader *header ) header->separate = TRUE; } - /* Stays zero if there's no SUBIFD. + /* TIFFGetField needs a uint16 to write count to. */ - TIFFGetField( rtiff->tiff, TIFFTAG_SUBIFD, - &header->subifd_count, &subifd_offsets ); + if( TIFFGetField( rtiff->tiff, TIFFTAG_SUBIFD, + &subifd_count, &subifd_offsets ) ) + header->subifd_count = subifd_count; /* IMAGEDESCRIPTION often has useful metadata. libtiff makes sure * that data is null-terminated and contains no embedded null diff --git a/libvips/foreign/vips2tiff.c b/libvips/foreign/vips2tiff.c index ca2e0c2b..cad90817 100644 --- a/libvips/foreign/vips2tiff.c +++ b/libvips/foreign/vips2tiff.c @@ -384,11 +384,6 @@ struct _Wtiff { * and we must compress ourselves. */ gboolean we_compress; - - /* If we are copying, we need a buffer to read the compressed tile to. - */ - tdata_t compressed_buf; - tsize_t compressed_buf_length; }; /* Write an ICC Profile from a file into the JPEG stream. @@ -959,20 +954,6 @@ wtiff_allocate_layers( Wtiff *wtiff ) return( -1 ); } - /* If we will be copying layers we need a buffer large enough to hold - * the largest compressed tile in any page. - * - * Allocate a buffer 2x the uncompressed tile size ... much simpler - * than searching every page for the largest tile with - * TIFFTAG_TILEBYTECOUNTS. - */ - if( wtiff->pyramid ) { - wtiff->compressed_buf_length = 2 * wtiff->tls * wtiff->tileh; - if( !(wtiff->compressed_buf = vips_malloc( NULL, - wtiff->compressed_buf_length )) ) - return( -1 ); - } - return( 0 ); } @@ -1032,7 +1013,6 @@ wtiff_free( Wtiff *wtiff ) VIPS_FREE( wtiff->tbuf ); VIPS_FREEF( layer_free_all, wtiff->layer ); VIPS_FREE( wtiff->filename ); - VIPS_FREE( wtiff->compressed_buf ); VIPS_FREE( wtiff ); } @@ -2029,12 +2009,17 @@ wtiff_copy_tiff( Wtiff *wtiff, TIFF *out, TIFF *in ) for( tile_no = 0; tile_no < n; tile_no++ ) { tsize_t len; - len = TIFFReadRawTile( in, tile_no, - wtiff->compressed_buf, wtiff->compressed_buf_length ); - if( len <= 0 || - TIFFWriteRawTile( out, tile_no, - wtiff->compressed_buf, len ) < 0 ) + /* TIFFReadRawTile()/TIFFWriteRawTile() would save us + * decompress/recompress, but they won't work for + * JPEG-compressed tiles since they won't copy the + * JPEG quant tables we need. + */ + len = TIFFReadEncodedTile( in, tile_no, buf, -1 ); + if( len < 0 || + TIFFWriteEncodedTile( out, tile_no, buf, len ) < 0 ) { + g_free( buf ); return( -1 ); + } } g_free( buf ); diff --git a/libvips/iofuncs/init.c b/libvips/iofuncs/init.c index 4700acac..e04cd34b 100644 --- a/libvips/iofuncs/init.c +++ b/libvips/iofuncs/init.c @@ -1161,7 +1161,7 @@ vips_guess_prefix( const char *argv0, const char *env_name ) /* Already set? */ - if( (prefix = g_getenv( env_name )) ) + if( (prefix = g_getenv( env_name )) ) return( prefix ); #ifdef G_OS_WIN32 diff --git a/test/test-suite/test_foreign.py b/test/test-suite/test_foreign.py index 0237c188..52bd7485 100644 --- a/test/test-suite/test_foreign.py +++ b/test/test-suite/test_foreign.py @@ -415,6 +415,12 @@ class TestForeign: im = pyvips.Image.new_from_file(TIF4_FILE) self.save_load_file(".tif", "[bitdepth=4]", im) + filename = temp_filename(self.tempdir, '.tif') + self.colour.write_to_file(filename, pyramid=True, compression="jpeg") + x = pyvips.Image.new_from_file(filename, page=2) + assert x.width == 72 + assert abs(x.avg() - 117.3) < 1 + filename = temp_filename(self.tempdir, '.tif') x = pyvips.Image.new_from_file(TIF_FILE) x = x.copy() @@ -895,6 +901,10 @@ class TestForeign: assert abs(im.width * 2 - x.width) < 2 assert abs(im.height * 2 - x.height) < 2 + with pytest.raises(pyvips.error.Error): + svg = b'' + im = pyvips.Image.new_from_buffer(svg, "") + def test_csv(self): self.save_load("%s.csv", self.mono)