From 070c9bd5a7124c9147b2a9738edb5d2cda6a3ba9 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 22 Apr 2014 10:43:13 +0100 Subject: [PATCH] add load from buffer --- ChangeLog | 1 + libvips/foreign/tiff2vips.c | 192 +++++++++++++++++++++++++++++------- 2 files changed, 159 insertions(+), 34 deletions(-) diff --git a/ChangeLog b/ChangeLog index fdfd72e4..7761c09a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -21,6 +21,7 @@ - vips_system() now supports many input images and you can change image argument order - support 16-bit palette TIFFs, plus palette TIFFs can have an alpha +- add vips_tiffload_buffer() 6/3/14 started 7.38.6 - grey ramp minimum was wrong diff --git a/libvips/foreign/tiff2vips.c b/libvips/foreign/tiff2vips.c index 1c0ce49a..9318679e 100644 --- a/libvips/foreign/tiff2vips.c +++ b/libvips/foreign/tiff2vips.c @@ -144,6 +144,8 @@ * 11/4/14 * - support 16 bits per sample palette images * - palette images can have an alpha + * 22/4/14 + * - add read from buffer */ /* @@ -208,6 +210,8 @@ typedef struct _ReadTiff { /* Parameters. */ char *filename; + void *buf; + size_t len; VipsImage *out; int page; gboolean readbehind; @@ -225,6 +229,10 @@ typedef struct _ReadTiff { */ gboolean memcpy; + /* The current 'file pointer' for memory buffers. + */ + size_t pos; + /* Geometry. */ uint32 twidth, theight; /* Tile size */ @@ -1635,15 +1643,16 @@ readtiff_destroy( VipsObject *object, ReadTiff *rtiff ) } static ReadTiff * -readtiff_new( const char *filename, VipsImage *out, int page, - gboolean readbehind ) +readtiff_new( VipsImage *out, int page, gboolean readbehind ) { ReadTiff *rtiff; if( !(rtiff = VIPS_NEW( out, ReadTiff )) ) return( NULL ); - rtiff->filename = vips_strdup( VIPS_OBJECT( out ), filename ); + rtiff->filename = NULL; + rtiff->buf = NULL; + rtiff->len = 0; rtiff->out = out; rtiff->page = page; rtiff->readbehind = readbehind; @@ -1651,6 +1660,7 @@ readtiff_new( const char *filename, VipsImage *out, int page, rtiff->sfn = NULL; rtiff->client = NULL; rtiff->memcpy = FALSE; + rtiff->pos = 0; rtiff->twidth = 0; rtiff->theight = 0; rtiff->separate = FALSE; @@ -1669,6 +1679,148 @@ readtiff_new( const char *filename, VipsImage *out, int page, return( rtiff ); } +static ReadTiff * +readtiff_new_filename( const char *filename, VipsImage *out, int page, + gboolean readbehind ) +{ + ReadTiff *rtiff; + int i; + + if( !(rtiff = readtiff_new_filename( out, page, readbehind )) ) + return( NULL ); + + rtiff->filename = vips_strdup( VIPS_OBJECT( out ), filename ); + + /* No mmap --- no performance advantage with libtiff, and it burns up + * our VM if the tiff file is large. + */ + if( !(rtiff->tiff = TIFFOpen( filename, "rm" )) ) { + vips_error( "tiff2vips", _( "unable to open \"%s\" for input" ), + filename ); + return( NULL ); + } + + for( i = 0; i < page; i++ ) + if( !TIFFReadDirectory( rtiff->tiff ) ) { + vips_error( "tiff2vips", + _( "TIFF does not contain page %d" ), + rtiff->page ); + return( NULL ); + } + + return( rtiff ); +} + +static tsize_t +my_tiff_read( thandle_t st, tdata_t buffer, tsize_t size ) +{ + ReadTiff *rtiff = (ReadTiff *) st; + + size_t available = rtiff->len - rtiff->pos; + size_t copy = VIPS_MIN( size, available ); + + memcpy( buffer, rtiff->buf + rtiff->pos, copy ); + rtiff->pos += copy; + + return( copy ); +} + +static tsize_t +my_tiff_write( thandle_t st, tdata_t buffer, tsize_t size ) +{ + ReadTiff *rtiff = (ReadTiff *) st; + + g_assert( 0 ); + + return( 0 ); +} + +static int +my_tiff_close( thandle_t ) +{ + ReadTiff *rtiff = (ReadTiff *) st; + + return 0; +} + +static toff_t +my_tiff_seek( thandle_t st, toff_t pos, int whence ) +{ + ReadTiff *rtiff = (ReadTiff *) st; + + if( whence == SEEK_SET ) + rtiff->pos = pos; + else if( whence == SEEK_CUR ) + rtiff->pos += pos; + else if( whence == SEEK_END ) + rtiff->pos = rtiff->len + pos; + else + g_assert( 0 ); + + return( rtiff->pos ); +} + +static toff_t +my_tiff_size( thandle_t st ) +{ + ReadTiff *rtiff = (ReadTiff *) st; + + return( rtiff->len ); +} + +static int +my_tiff_map( thandle_t, tdata_t *, toff_t * ) +{ + ReadTiff *rtiff = (ReadTiff *) st; + + g_assert( 0 ); + + return 0; +} + +static void +my_tiff_unmap( thandle_t, tdata_t, toff_t ) +{ + ReadTiff *rtiff = (ReadTiff *) st; + + g_assert( 0 ); + + return; +} + +static ReadTiff * +readtiff_new_buffer( void *buf, size_t len, VipsImage *out, int page, + gboolean readbehind ) +{ + ReadTiff *rtiff; + int i; + + if( !(rtiff = readtiff_new( out, page, readbehind )) ) + return( NULL ); + + rtiff->buf = buf; + rtiff->len = len; + + if( !(rtiff->tiff = TIFFClientOpen( "Memory", "w", + (thandle_t) rtiff, + my_tiff_read, my_tiff_write, my_tiff_seek, my_tiff_close, + my_tiff_size, my_tiff_map, my_tiff_unmap )) ) { + vips_error( "tiff2vips", "%s", + _( "unable to open memory buffer for input" ) ); + return( NULL ); + } + + for( i = 0; i < page; i++ ) + if( !TIFFReadDirectory( rtiff->tiff ) ) { + vips_error( "tiff2vips", + _( "TIFF does not contain page %d" ), + rtiff->page ); + return( NULL ); + } + + return( rtiff ); +} + /* Pull out the nth directory from a TIFF file. */ static TIFF * @@ -1732,15 +1884,10 @@ vips__tiff_read( const char *filename, VipsImage *out, int page, vips__tiff_init(); - if( !(rtiff = readtiff_new( filename, out, page, readbehind )) ) + if( !(rtiff = readtiff_new_filename( filename, + out, page, readbehind )) ) return( -1 ); - if( !(rtiff->tiff = get_directory( rtiff->filename, rtiff->page )) ) { - vips_error( "tiff2vips", _( "TIFF file does not " - "contain page %d" ), rtiff->page ); - return( -1 ); - } - if( TIFFIsTiled( rtiff->tiff ) ) { if( read_tilewise( rtiff, out ) ) return( -1 ); @@ -1760,16 +1907,9 @@ vips__tiff_read_header( const char *filename, VipsImage *out, int page ) vips__tiff_init(); - if( !(rtiff = readtiff_new( filename, out, page, FALSE )) ) + if( !(rtiff = readtiff_new_filename( filename, out, page, FALSE )) ) return( -1 ); - if( !(rtiff->tiff = get_directory( rtiff->filename, rtiff->page )) ) { - vips_error( "tiff2vips", - _( "TIFF file does not contain page %d" ), - rtiff->page ); - return( -1 ); - } - if( parse_header( rtiff, out ) ) return( -1 ); @@ -1814,19 +1954,9 @@ vips__tiff_read_header_buffer( void *buf, size_t len, VipsImage *out, int page ) vips__tiff_init(); - move the TIFFOpen into readtiff_new - - put the get_dir in there as well - if( !(rtiff = readtiff_new_buffer( buf, len, out, page, FALSE )) ) return( -1 ); - if( !(rtiff->tiff = get_directory( rtiff, rtiff->page )) ) { - vips_error( "tiff2vips", - _( "TIFF does not contain page %d" ), rtiff->page ); - return( -1 ); - } - if( parse_header( rtiff, out ) ) return( -1 ); @@ -1849,12 +1979,6 @@ vips__tiff_read_buffer( void *buf, size_t len, VipsImage *out, if( !(rtiff = readtiff_new_buffer( buf, len, out, page, readbehind )) ) return( -1 ); - if( !(rtiff->tiff = get_directory( rtiff, rtiff->page )) ) { - vips_error( "tiff2vips", - _( "TIFF does not contain page %d" ), rtiff->page ); - return( -1 ); - } - if( TIFFIsTiled( rtiff->tiff ) ) { if( read_tilewise( rtiff, out ) ) return( -1 );