From 9ea66365c4b8b20ea9d3dd2ed17e815627ac439b Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 29 Jul 2010 10:51:51 +0000 Subject: [PATCH] add rd mode to im_open() --- ChangeLog | 1 + TODO | 1 + libvips/iofuncs/im_open.c | 87 +++++++++++++++++++++++++++++++-------- 3 files changed, 72 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index efaa7348..43fc3592 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,7 @@ image and header - added im_vips2bufpng() - use GetTempPath() to pick a temp dir on Windows +- added "rd" mode to im_open() 12/5/10 started 7.22.2 - the conditional image of ifthenelse can be any format, a (!=0) is added if diff --git a/TODO b/TODO index f2e8fb26..a0f3b9d7 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,4 @@ +- vipsthumbnail should use "rd" mode - lcms2 needs testing diff --git a/libvips/iofuncs/im_open.c b/libvips/iofuncs/im_open.c index 2ed70d6e..5c6e9458 100644 --- a/libvips/iofuncs/im_open.c +++ b/libvips/iofuncs/im_open.c @@ -195,14 +195,12 @@ attach_sb( IMAGE *out, int (*save_fn)(), const char *filename ) * delay actually decoding pixels until the first call to a start function. */ -typedef int (*OpenLazyFn)( const char *filename, IMAGE *im ); - /* What we track during a delayed open. */ typedef struct _OpenLazy { char *filename; - OpenLazyFn read_pixels; /* Read in pixels with this */ + VipsFormatClass *format;/* Read in pixels with this */ IMAGE *lazy_im; /* Image we read to .. copy from this */ } OpenLazy; @@ -216,7 +214,7 @@ open_lazy_start( IMAGE *out, void *a, void *dummy ) if( !lazy->lazy_im ) { if( !(lazy->lazy_im = im_open_local( out, "read", "p" )) || - lazy->read_pixels( lazy->filename, lazy->lazy_im ) ) { + lazy->format->load( lazy->filename, lazy->lazy_im ) ) { IM_FREEF( im_close, lazy->lazy_im ); return( NULL ); } @@ -251,18 +249,17 @@ open_lazy_generate( REGION *or, void *seq, void *a, void *b ) * decoding pixels with the second OpenLazyFn until the first generate(). */ static int -open_lazy( OpenLazyFn read_header, OpenLazyFn read_pixels, - const char *filename, IMAGE *out ) +open_lazy( VipsFormatClass *format, const char *filename, IMAGE *out ) { OpenLazy *lazy = IM_NEW( out, OpenLazy ); if( !lazy || !(lazy->filename = im_strdup( out, filename )) ) return( -1 ); - lazy->read_pixels = read_pixels; + lazy->format = format; lazy->lazy_im = NULL; - if( read_header( filename, out ) || + if( format->header( filename, out ) || im_demand_hint( out, IM_ANY, NULL ) ) return( -1 ); @@ -274,13 +271,55 @@ open_lazy( OpenLazyFn read_header, OpenLazyFn read_pixels, return( 0 ); } -static IMAGE * -open_sub( OpenLazyFn read_header, OpenLazyFn read_pixels, const char *filename ) +static size_t +guess_size( VipsFormatClass *format, const char *filename ) { IMAGE *im; + size_t size; - if( !(im = im_open( filename, "p" )) || - open_lazy( read_header, read_pixels, filename, im ) ) { + if( !(im = im_open( "header", "p" )) ) + return( 0 ); + if( format->header( filename, im ) ) { + im_close( im ); + return( 0 ); + } + size = IM_IMAGE_SIZEOF_LINE( im ) * im->Ysize; + im_close( im ); + + return( size ); +} + +static IMAGE * +open_sub( VipsFormatClass *format, const char *filename, gboolean disc ) +{ + static const int use_disc_threshold = 1024 * 1024; + + IMAGE *im; + + /* We open to disc if: + * - 'disc' is set + * - the format does not support lazy read + * - the image will be more than a megabyte, uncompressed + */ + im = NULL; + if( disc ) + if( !(vips_format_get_flags( format, filename ) & + VIPS_FORMAT_PARTIAL) ) { + size_t size; + + size = guess_size( format, filename ); + if( size > use_disc_threshold ) + if( !(im = im__open_temp( "%s.v" )) ) + return( NULL ); + } + + /* Otherwise, fall back to a "p". + */ + if( !im && + !(im = im_open( filename, "p" )) ) + return( NULL ); + + if( open_lazy( format, filename, im ) ) { im_close( im ); return( NULL ); } @@ -353,9 +392,10 @@ evalend_cb( Progress *progress ) * file for you in memory. * * For some large files (eg. TIFF) this may - * not be what you want: you should call the appropriate converter - * yourself, and arrange for the conversion to take place on disc. - * See #VipsFormat. + * not be what you want, it can fill memory very quickly. Instead, you + * can either use "rd" mode (see below), or you can use the lower-level + * API and control the loading process yourself. See + * #VipsFormat. * * im_open() can read files in most formats. * @@ -366,6 +406,19 @@ evalend_cb( Progress *progress ) * * * + * "rd" + * opens the named file for reading. If the uncompressed image is larger + * than a megabyte and the file format does not support random access, + * rather than uncompressing to memory, im_open() will uncompress to a + * temporary disc file. This file will be automatically deleted when the + * IMAGE is closed. + * + * See im_system_image() for an explanation of how VIPS selects a + * location for the temporary file. + * + * + * + * * "w" * opens the named file for writing. It looks at the file name * suffix to determine the type to write -- for example: @@ -440,8 +493,8 @@ im_open( const char *filename, const char *mode ) if( !(im = im_open_vips( filename )) ) return( NULL ); } - else if( !(im = open_sub( - format->header, format->load, filename )) ) + else if( !(im = open_sub( format, filename, + mode[1] == 'd' )) ) return( NULL ); } else