diff --git a/libvips/deprecated/im_tiff2vips.c b/libvips/deprecated/im_tiff2vips.c index b082a443..8a25790d 100644 --- a/libvips/deprecated/im_tiff2vips.c +++ b/libvips/deprecated/im_tiff2vips.c @@ -52,6 +52,56 @@ #include "../foreign/pforeign.h" +#ifdef HAVE_TIFF +static gboolean +im_istifftiled( const char *filename ) +{ + VipsStreamInput *input; + gboolean result; + + if( !(input = vips_stream_input_new_from_filename( filename )) ) + return( FALSE ); + result = vips__istiff_stream( input ); + VIPS_UNREF( input ); + + return( result ); +} + +static int +im_tiff_read_header( const char *filename, VipsImage *out, + int page, int n, gboolean autorotate ) +{ + VipsStreamInput *input; + + if( !(input = vips_stream_input_new_from_filename( filename )) ) + return( -1 ); + if( vips__tiff_read_header_stream( input, out, page, n, autorotate ) ) { + VIPS_UNREF( input ); + return( -1 ); + } + VIPS_UNREF( input ); + + return( 0 ); +} + +static int +im_tiff_read( const char *filename, VipsImage *out, + int page, int n, gboolean autorotate ) +{ + VipsStreamInput *input; + + if( !(input = vips_stream_input_new_from_filename( filename )) ) + return( -1 ); + if( vips__tiff_read_stream( input, out, page, n, autorotate ) ) { + VIPS_UNREF( input ); + return( -1 ); + } + VIPS_UNREF( input ); + + return( 0 ); +} +#endif /*HAVE_TIFF*/ + static int tiff2vips( const char *name, IMAGE *out, gboolean header_only ) { @@ -88,18 +138,18 @@ tiff2vips( const char *name, IMAGE *out, gboolean header_only ) if( !header_only && !seq && - !vips__istifftiled( filename ) && + !im_istifftiled( filename ) && out->dtype == VIPS_IMAGE_PARTIAL ) { if( vips__image_wio_output( out ) ) return( -1 ); } if( header_only ) { - if( vips__tiff_read_header( filename, out, page, 1, FALSE ) ) + if( im_tiff_read_header( filename, out, page, 1, FALSE ) ) return( -1 ); } else { - if( vips__tiff_read( filename, out, page, 1, FALSE ) ) + if( im_tiff_read( filename, out, page, 1, FALSE ) ) return( -1 ); } #else diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index d72a9744..809d2810 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -2007,6 +2007,7 @@ vips_foreign_operation_init( void ) extern GType vips_foreign_save_jpeg_mime_get_type( void ); extern GType vips_foreign_load_tiff_file_get_type( void ); extern GType vips_foreign_load_tiff_buffer_get_type( void ); + extern GType vips_foreign_load_tiff_stream_get_type( void ); extern GType vips_foreign_save_tiff_file_get_type( void ); extern GType vips_foreign_save_tiff_buffer_get_type( void ); extern GType vips_foreign_load_vips_get_type( void ); @@ -2135,6 +2136,7 @@ vips_foreign_operation_init( void ) #ifdef HAVE_TIFF vips_foreign_load_tiff_file_get_type(); vips_foreign_load_tiff_buffer_get_type(); + vips_foreign_load_tiff_stream_get_type(); vips_foreign_save_tiff_file_get_type(); vips_foreign_save_tiff_buffer_get_type(); #endif /*HAVE_TIFF*/ diff --git a/libvips/foreign/pforeign.h b/libvips/foreign/pforeign.h index 3c6be4b6..40bf67df 100644 --- a/libvips/foreign/pforeign.h +++ b/libvips/foreign/pforeign.h @@ -79,22 +79,6 @@ int vips__tiff_write_buf( VipsImage *in, VipsRegionShrink region_shrink, int level, gboolean lossless ); -int vips__tiff_read_header( const char *filename, VipsImage *out, - int page, int n, gboolean autorotate ); -int vips__tiff_read( const char *filename, VipsImage *out, - int page, int n, gboolean autorotate ); - -gboolean vips__istiff( const char *filename ); -gboolean vips__istifftiled( const char *filename ); - -gboolean vips__istiff_buffer( const void *buf, size_t len ); -gboolean vips__istifftiled_buffer( const void *buf, size_t len ); - -int vips__tiff_read_header_buffer( const void *buf, size_t len, VipsImage *out, - int page, int n, gboolean autorotate ); -int vips__tiff_read_buffer( const void *buf, size_t len, VipsImage *out, - int page, int n, gboolean autorotate ); - gboolean vips__istiff_stream( VipsStreamInput *input ); gboolean vips__istifftiled_stream( VipsStreamInput *input ); int vips__tiff_read_header_stream( VipsStreamInput *input, VipsImage *out, diff --git a/libvips/foreign/tiff.c b/libvips/foreign/tiff.c index b0fe5339..879e6611 100644 --- a/libvips/foreign/tiff.c +++ b/libvips/foreign/tiff.c @@ -132,174 +132,6 @@ vips__tiff_openout( const char *path, gboolean bigtiff ) return( tif ); } -/* Open TIFF for input from a file. - */ -TIFF * -vips__tiff_openin( const char *path ) -{ - /* No mmap --- no performance advantage with libtiff, and it burns up - * our VM if the tiff file is large. - */ - const char *mode = "rm"; - - TIFF *tif; - -#ifdef DEBUG - printf( "vips__tiff_openin( \"%s\" )\n", path ); -#endif /*DEBUG*/ - - /* Need the utf-16 version on Windows. - */ -#ifdef OS_WIN32 -{ - GError *error = NULL; - wchar_t *path16; - - if( !(path16 = (wchar_t *) - g_utf8_to_utf16( path, -1, NULL, NULL, &error )) ) { - vips_g_error( &error ); - return( NULL ); - } - - tif = TIFFOpenW( path16, mode ); - - g_free( path16 ); -} -#else /*!OS_WIN32*/ - tif = TIFFOpen( path, mode ); -#endif /*OS_WIN32*/ - - if( !tif ) { - vips_error( "tiff", - _( "unable to open \"%s\" for input" ), path ); - return( NULL ); - } - - return( tif ); -} - -/* TIFF input from a memory buffer. - */ - -typedef struct _VipsTiffOpeninBuffer { - size_t position; - const void *data; - size_t length; -} VipsTiffOpeninBuffer; - -static tsize_t -openin_buffer_read( thandle_t st, tdata_t data, tsize_t size ) -{ - VipsTiffOpeninBuffer *buffer = (VipsTiffOpeninBuffer *) st; - - size_t available; - size_t copied; - - if( buffer->position > buffer->length ) { - vips_error( "openin_buffer_read", - "%s", _( "read beyond end of buffer" ) ); - return( 0 ); - } - - available = buffer->length - buffer->position; - copied = VIPS_MIN( size, available ); - memcpy( data, - (unsigned char *) buffer->data + buffer->position, copied ); - buffer->position += copied; - - return( copied ); -} - -static tsize_t -openin_buffer_write( thandle_t st, tdata_t buffer, tsize_t size ) -{ - g_assert_not_reached(); - - return( 0 ); -} - -static int -openin_buffer_close( thandle_t st ) -{ - return( 0 ); -} - -/* After calling this, ->pos is not bound by the size of the buffer, it can - * have any positive value. - */ -static toff_t -openin_buffer_seek( thandle_t st, toff_t position, int whence ) -{ - VipsTiffOpeninBuffer *buffer = (VipsTiffOpeninBuffer *) st; - - if( whence == SEEK_SET ) - buffer->position = position; - else if( whence == SEEK_CUR ) - buffer->position += position; - else if( whence == SEEK_END ) - buffer->position = buffer->length + position; - else - g_assert_not_reached(); - - return( buffer->position ); -} - -static toff_t -openin_buffer_size( thandle_t st ) -{ - VipsTiffOpeninBuffer *buffer = (VipsTiffOpeninBuffer *) st; - - return( buffer->length ); -} - -static int -openin_buffer_map( thandle_t st, tdata_t *start, toff_t *len ) -{ - g_assert_not_reached(); - - return( 0 ); -} - -static void -openin_buffer_unmap( thandle_t st, tdata_t start, toff_t len ) -{ - g_assert_not_reached(); - - return; -} - -TIFF * -vips__tiff_openin_buffer( VipsImage *image, const void *data, size_t length ) -{ - VipsTiffOpeninBuffer *buffer; - TIFF *tiff; - -#ifdef DEBUG - printf( "vips__tiff_openin_buffer:\n" ); -#endif /*DEBUG*/ - - buffer = VIPS_NEW( image, VipsTiffOpeninBuffer ); - buffer->position = 0; - buffer->data = data; - buffer->length = length; - - if( !(tiff = TIFFClientOpen( "memory input", "rm", - (thandle_t) buffer, - openin_buffer_read, - openin_buffer_write, - openin_buffer_seek, - openin_buffer_close, - openin_buffer_size, - openin_buffer_map, - openin_buffer_unmap )) ) { - vips_error( "vips__tiff_openin_buffer", "%s", - _( "unable to open memory buffer for input" ) ); - return( NULL ); - } - - return( tiff ); -} - /* TIFF input from a vips stream. */ @@ -365,18 +197,20 @@ openin_stream_unmap( thandle_t st, tdata_t start, toff_t len ) } TIFF * -vips__tiff_openin_stream( VipsImage *image, VipsStreamInput *input ) +vips__tiff_openin_stream( VipsStreamInput *input ) { TIFF *tiff; #ifdef DEBUG - printf( "vips__tiff_openin_buffer:\n" ); + printf( "vips__tiff_openin_stream:\n" ); #endif /*DEBUG*/ /* Unreffed on close(), see above. */ - g_object_ref( input ); + if( vips_stream_input_rewind( input ) ) + return( NULL ); + g_object_ref( input ); if( !(tiff = TIFFClientOpen( "stream input", "rm", (thandle_t) input, openin_stream_read, diff --git a/libvips/foreign/tiff.h b/libvips/foreign/tiff.h index b1681dd2..441d3c64 100644 --- a/libvips/foreign/tiff.h +++ b/libvips/foreign/tiff.h @@ -37,15 +37,12 @@ extern "C" { #endif /*__cplusplus*/ -TIFF *vips__tiff_openout( const char *path, gboolean bigtiff ); -TIFF *vips__tiff_openin( const char *path ); +TIFF *vips__tiff_openin_stream( VipsStreamInput *input ); -TIFF *vips__tiff_openin_buffer( VipsImage *image, - const void *data, size_t length ); +TIFF *vips__tiff_openout( const char *path, gboolean bigtiff ); TIFF *vips__tiff_openout_buffer( VipsImage *image, gboolean bigtiff, void **out_data, size_t *out_length ); -TIFF *vips__tiff_openin_stream( VipsImage *image, VipsStreamInput *input ); #ifdef __cplusplus } diff --git a/libvips/foreign/tiff2vips.c b/libvips/foreign/tiff2vips.c index 01d0fbf6..ecf24463 100644 --- a/libvips/foreign/tiff2vips.c +++ b/libvips/foreign/tiff2vips.c @@ -189,6 +189,8 @@ * 7/6/19 * - istiff reads the first directory rather than just testing the magic * number, so it ignores more TIFF-like, but not TIFF images + * 17/10/19 + * - switch to stream input */ /* @@ -2341,68 +2343,6 @@ rtiff_header_read_all( Rtiff *rtiff ) return( 0 ); } -static Rtiff * -rtiff_new_filename( const char *filename, VipsImage *out, - int page, int n, gboolean autorotate ) -{ - Rtiff *rtiff; - - if( !(rtiff = rtiff_new( out, page, n, autorotate )) || - !(rtiff->tiff = vips__tiff_openin( filename )) || - rtiff_header_read_all( rtiff ) ) - return( NULL ); - - rtiff->filename = vips_strdup( VIPS_OBJECT( out ), filename ); - - return( rtiff ); -} - -static Rtiff * -rtiff_new_buffer( const void *buf, size_t len, VipsImage *out, - int page, int n, gboolean autorotate ) -{ - Rtiff *rtiff; - - if( !(rtiff = rtiff_new( out, page, n, autorotate )) || - !(rtiff->tiff = vips__tiff_openin_buffer( out, buf, len )) || - rtiff_header_read_all( rtiff ) ) - return( NULL ); - - return( rtiff ); -} - -/* For istiffpyramid(), see vips_thumbnail_get_tiff_pyramid(). - */ - -int -vips__tiff_read( const char *filename, VipsImage *out, - int page, int n, gboolean autorotate ) -{ - Rtiff *rtiff; - -#ifdef DEBUG - printf( "tiff2vips: libtiff version is \"%s\"\n", TIFFGetVersion() ); - printf( "tiff2vips: libtiff starting for %s\n", filename ); -#endif /*DEBUG*/ - - vips__tiff_init(); - - if( !(rtiff = rtiff_new_filename( filename, out, - page, n, autorotate )) ) - return( -1 ); - - if( rtiff->header.tiled ) { - if( rtiff_read_tilewise( rtiff, out ) ) - return( -1 ); - } - else { - if( rtiff_read_stripwise( rtiff, out ) ) - return( -1 ); - } - - return( 0 ); -} - /* On a header-only read, we can just swap width/height if orientation is 6 or * 8. */ @@ -2426,186 +2366,17 @@ vips__tiff_read_header_orientation( Rtiff *rtiff, VipsImage *out ) } } -int -vips__tiff_read_header( const char *filename, VipsImage *out, - int page, int n, gboolean autorotate ) -{ - Rtiff *rtiff; - - vips__tiff_init(); - - if( !(rtiff = - rtiff_new_filename( filename, out, page, n, autorotate )) ) - return( -1 ); - - if( rtiff_set_header( rtiff, out ) ) - return( -1 ); - - vips__tiff_read_header_orientation( rtiff, out ); - - /* Just a header read: we can free the tiff read early and save an fd. - */ - rtiff_free( rtiff ); - - return( 0 ); -} - typedef gboolean (*TiffPropertyFn)( TIFF *tif ); -static gboolean -vips__testtiff( const char *filename, TiffPropertyFn fn ) -{ - TIFF *tif; - gboolean property; - - vips__tiff_init(); - - if( !(tif = vips__tiff_openin( filename )) ) { - vips_error_clear(); - return( FALSE ); - } - - property = fn ? fn( tif ) : TRUE; - - TIFFClose( tif ); - - return( property ); -} - -gboolean -vips__testtiff_buffer( const void *buf, size_t len, TiffPropertyFn fn ) -{ - VipsImage *im; - TIFF *tif; - gboolean property; - - vips__tiff_init(); - - im = vips_image_new(); - - if( !(tif = vips__tiff_openin_buffer( im, buf, len )) ) { - g_object_unref( im ); - vips_error_clear(); - return( FALSE ); - } - - property = fn ? fn( tif ) : TRUE; - - TIFFClose( tif ); - g_object_unref( im ); - - return( property ); -} - -gboolean -vips__istifftiled( const char *filename ) -{ - return( vips__testtiff( filename, TIFFIsTiled ) ); -} - -/* We test for TIFF by trying to read the first directory. We could just test - * the magic number, but many formats (eg. ARW) use a TIFF-like container and - * we don't want to open those with vips tiffload. - */ -gboolean -vips__istiff( const char *filename ) -{ - return( vips__testtiff( filename, NULL ) ); -} - -gboolean -vips__istiff_buffer( const void *buf, size_t len ) -{ - return( vips__testtiff_buffer( buf, len, NULL ) ); -} - -int -vips__tiff_read_header_buffer( const void *buf, size_t len, VipsImage *out, - int page, int n, gboolean autorotate ) -{ - Rtiff *rtiff; - - vips__tiff_init(); - - if( !(rtiff = rtiff_new_buffer( buf, len, out, page, n, autorotate )) ) - return( -1 ); - - if( rtiff_set_header( rtiff, out ) ) - return( -1 ); - - vips__tiff_read_header_orientation( rtiff, out ); - - return( 0 ); -} - -int -vips__tiff_read_buffer( const void *buf, size_t len, - VipsImage *out, int page, int n, gboolean autorotate ) -{ - Rtiff *rtiff; - -#ifdef DEBUG - printf( "tiff2vips: libtiff version is \"%s\"\n", TIFFGetVersion() ); - printf( "tiff2vips: libtiff starting for buffer %p\n", buf ); -#endif /*DEBUG*/ - - vips__tiff_init(); - - if( !(rtiff = rtiff_new_buffer( buf, len, out, page, n, autorotate )) ) - return( -1 ); - - if( rtiff->header.tiled ) { - if( rtiff_read_tilewise( rtiff, out ) ) - return( -1 ); - } - else { - if( rtiff_read_stripwise( rtiff, out ) ) - return( -1 ); - } - - return( 0 ); -} - -gboolean -vips__istifftiled_buffer( const void *buf, size_t len ) -{ - VipsImage *im; - TIFF *tif; - gboolean tiled; - - vips__tiff_init(); - - im = vips_image_new(); - - if( !(tif = vips__tiff_openin_buffer( im, buf, len )) ) { - g_object_unref( im ); - vips_error_clear(); - return( FALSE ); - } - - tiled = TIFFIsTiled( tif ); - - TIFFClose( tif ); - g_object_unref( im ); - - return( tiled ); -} - static gboolean vips__testtiff_stream( VipsStreamInput *input, TiffPropertyFn fn ) { - VipsImage *im; TIFF *tif; gboolean property; vips__tiff_init(); - im = vips_image_new(); - - if( vips_stream_input_rewind( input ) ) - return( FALSE ); - if( !(tif = vips__tiff_openin_stream( im, input )) ) { - g_object_unref( im ); + if( !(tif = vips__tiff_openin_stream( input )) ) { vips_error_clear(); return( FALSE ); } @@ -2613,7 +2384,6 @@ vips__testtiff_stream( VipsStreamInput *input, TiffPropertyFn fn ) property = fn ? fn( tif ) : TRUE; TIFFClose( tif ); - g_object_unref( im ); return( property ); } @@ -2637,7 +2407,7 @@ rtiff_new_stream( VipsStreamInput *input, VipsImage *out, Rtiff *rtiff; if( !(rtiff = rtiff_new( out, page, n, autorotate )) || - !(rtiff->tiff = vips__tiff_openin_stream( out, input )) || + !(rtiff->tiff = vips__tiff_openin_stream( input )) || rtiff_header_read_all( rtiff ) ) return( NULL ); diff --git a/libvips/foreign/tiffload.c b/libvips/foreign/tiffload.c index 0271d94d..48553e83 100644 --- a/libvips/foreign/tiffload.c +++ b/libvips/foreign/tiffload.c @@ -138,17 +138,37 @@ typedef VipsForeignLoadTiffClass VipsForeignLoadTiffFileClass; G_DEFINE_TYPE( VipsForeignLoadTiffFile, vips_foreign_load_tiff_file, vips_foreign_load_tiff_get_type() ); +static gboolean +vips_foreign_load_tiff_file_is_a( const char *filename ) +{ + VipsStreamInput *input; + gboolean result; + + if( !(input = vips_stream_input_new_from_filename( filename )) ) + return( FALSE ); + result = vips__istiff_stream( input ); + VIPS_UNREF( input ); + + return( result ); +} + static VipsForeignFlags vips_foreign_load_tiff_file_get_flags_filename( const char *filename ) { + VipsStreamInput *input; VipsForeignFlags flags; + if( !(input = vips_stream_input_new_from_filename( filename )) ) + return( 0 ); + flags = 0; - if( vips__istifftiled( filename ) ) + if( vips__istifftiled_stream( input ) ) flags |= VIPS_FOREIGN_PARTIAL; else flags |= VIPS_FOREIGN_SEQUENTIAL; + VIPS_UNREF( input ); + return( flags ); } @@ -167,9 +187,16 @@ vips_foreign_load_tiff_file_header( VipsForeignLoad *load ) VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) load; VipsForeignLoadTiffFile *file = (VipsForeignLoadTiffFile *) load; - if( vips__tiff_read_header( file->filename, load->out, - tiff->page, tiff->n, tiff->autorotate ) ) + VipsStreamInput *input; + + if( !(input = vips_stream_input_new_from_filename( file->filename )) ) return( -1 ); + if( vips__tiff_read_header_stream( input, load->out, + tiff->page, tiff->n, tiff->autorotate ) ) { + VIPS_UNREF( input ); + return( -1 ); + } + VIPS_UNREF( input ); VIPS_SETSTR( load->out->filename, file->filename ); @@ -182,9 +209,16 @@ vips_foreign_load_tiff_file_load( VipsForeignLoad *load ) VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) load; VipsForeignLoadTiffFile *file = (VipsForeignLoadTiffFile *) load; - if( vips__tiff_read( file->filename, load->real, - tiff->page, tiff->n, tiff->autorotate ) ) + VipsStreamInput *input; + + if( !(input = vips_stream_input_new_from_filename( file->filename )) ) return( -1 ); + if( vips__tiff_read_stream( input, load->real, + tiff->page, tiff->n, tiff->autorotate ) ) { + VIPS_UNREF( input ); + return( -1 ); + } + VIPS_UNREF( input ); return( 0 ); } @@ -211,7 +245,7 @@ vips_foreign_load_tiff_file_class_init( VipsForeignLoadTiffFileClass *class ) foreign_class->suffs = vips__foreign_tiff_suffs; - load_class->is_a = vips__istiff; + load_class->is_a = vips_foreign_load_tiff_file_is_a; load_class->get_flags_filename = vips_foreign_load_tiff_file_get_flags_filename; load_class->get_flags = vips_foreign_load_tiff_file_get_flags; @@ -245,18 +279,37 @@ typedef VipsForeignLoadTiffClass VipsForeignLoadTiffBufferClass; G_DEFINE_TYPE( VipsForeignLoadTiffBuffer, vips_foreign_load_tiff_buffer, vips_foreign_load_tiff_get_type() ); +static gboolean +vips_foreign_load_tiff_buffer_is_a_buffer( const void *buf, size_t len ) +{ + VipsStreamInput *input; + gboolean result; + + if( !(input = vips_stream_input_new_from_memory( buf, len )) ) + return( FALSE ); + result = vips__istiff_stream( input ); + VIPS_UNREF( input ); + + return( result ); +} + static VipsForeignFlags vips_foreign_load_tiff_buffer_get_flags( VipsForeignLoad *load ) { VipsForeignLoadTiffBuffer *buffer = (VipsForeignLoadTiffBuffer *) load; + VipsStreamInput *input; VipsForeignFlags flags; + if( !(input = vips_stream_input_new_from_memory( + buffer->buf->data, buffer->buf->length )) ) + return( FALSE ); flags = 0; - if( vips__istifftiled_buffer( buffer->buf->data, buffer->buf->length ) ) + if( vips__istifftiled_stream( input ) ) flags |= VIPS_FOREIGN_PARTIAL; else flags |= VIPS_FOREIGN_SEQUENTIAL; + VIPS_UNREF( input ); return( flags ); } @@ -267,10 +320,17 @@ vips_foreign_load_tiff_buffer_header( VipsForeignLoad *load ) VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) load; VipsForeignLoadTiffBuffer *buffer = (VipsForeignLoadTiffBuffer *) load; - if( vips__tiff_read_header_buffer( - buffer->buf->data, buffer->buf->length, load->out, - tiff->page, tiff->n, tiff->autorotate ) ) + VipsStreamInput *input; + + if( !(input = vips_stream_input_new_from_memory( + buffer->buf->data, buffer->buf->length )) ) + return( FALSE ); + if( vips__tiff_read_header_stream( input, load->out, + tiff->page, tiff->n, tiff->autorotate ) ) { + VIPS_UNREF( input ); return( -1 ); + } + VIPS_UNREF( input ); return( 0 ); } @@ -281,10 +341,17 @@ vips_foreign_load_tiff_buffer_load( VipsForeignLoad *load ) VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) load; VipsForeignLoadTiffBuffer *buffer = (VipsForeignLoadTiffBuffer *) load; - if( vips__tiff_read_buffer( - buffer->buf->data, buffer->buf->length, load->real, - tiff->page, tiff->n, tiff->autorotate ) ) + VipsStreamInput *input; + + if( !(input = vips_stream_input_new_from_memory( + buffer->buf->data, buffer->buf->length )) ) + return( FALSE ); + if( vips__tiff_read_stream( input, load->real, + tiff->page, tiff->n, tiff->autorotate ) ) { + VIPS_UNREF( input ); return( -1 ); + } + VIPS_UNREF( input ); return( 0 ); } @@ -303,7 +370,7 @@ vips_foreign_load_tiff_buffer_class_init( object_class->nickname = "tiffload_buffer"; object_class->description = _( "load tiff from buffer" ); - load_class->is_a_buffer = vips__istiff_buffer; + load_class->is_a_buffer = vips_foreign_load_tiff_buffer_is_a_buffer; load_class->get_flags = vips_foreign_load_tiff_buffer_get_flags; load_class->header = vips_foreign_load_tiff_buffer_header; load_class->load = vips_foreign_load_tiff_buffer_load; @@ -321,6 +388,96 @@ vips_foreign_load_tiff_buffer_init( VipsForeignLoadTiffBuffer *buffer ) { } +typedef struct _VipsForeignLoadTiffStream { + VipsForeignLoadTiff parent_object; + + /* Load from a stream. + */ + VipsStreamInput *input; + +} VipsForeignLoadTiffStream; + +typedef VipsForeignLoadTiffClass VipsForeignLoadTiffStreamClass; + +G_DEFINE_TYPE( VipsForeignLoadTiffStream, vips_foreign_load_tiff_stream, + vips_foreign_load_tiff_get_type() ); + +static VipsForeignFlags +vips_foreign_load_tiff_stream_get_flags( VipsForeignLoad *load ) +{ + VipsForeignLoadTiffStream *stream = (VipsForeignLoadTiffStream *) load; + + VipsForeignFlags flags; + + flags = 0; + if( vips__istifftiled_stream( stream->input ) ) + flags |= VIPS_FOREIGN_PARTIAL; + else + flags |= VIPS_FOREIGN_SEQUENTIAL; + + return( flags ); +} + +static int +vips_foreign_load_tiff_stream_header( VipsForeignLoad *load ) +{ + VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) load; + VipsForeignLoadTiffStream *stream = (VipsForeignLoadTiffStream *) load; + + if( vips__tiff_read_header_stream( stream->input, load->out, + tiff->page, tiff->n, tiff->autorotate ) ) + return( -1 ); + + return( 0 ); +} + +static int +vips_foreign_load_tiff_stream_load( VipsForeignLoad *load ) +{ + VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) load; + VipsForeignLoadTiffStream *stream = (VipsForeignLoadTiffStream *) load; + + if( vips__tiff_read_stream( stream->input, load->real, + tiff->page, tiff->n, tiff->autorotate ) ) + return( -1 ); + + return( 0 ); +} + +static void +vips_foreign_load_tiff_stream_class_init( + VipsForeignLoadTiffStreamClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + object_class->nickname = "tiffload_stream"; + object_class->description = _( "load tiff from stream" ); + + load_class->is_a_stream = vips__istiff_stream; + load_class->get_flags = vips_foreign_load_tiff_stream_get_flags; + load_class->header = vips_foreign_load_tiff_stream_header; + load_class->load = vips_foreign_load_tiff_stream_load; + + VIPS_ARG_OBJECT( class, "input", 1, + _( "Input" ), + _( "Stream to load from" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsForeignLoadTiffStream, input ), + VIPS_TYPE_STREAM_INPUT ); + +} + +static void +vips_foreign_load_tiff_stream_init( VipsForeignLoadTiffStream *stream ) +{ +} + + #endif /*HAVE_TIFF*/ /** @@ -426,3 +583,35 @@ vips_tiffload_buffer( void *buf, size_t len, VipsImage **out, ... ) return( result ); } + +/** + * vips_tiffload_stream: + * @input: stream to load + * @out: (out): image to write + * @...: %NULL-terminated list of optional named arguments + * + * Optional arguments: + * + * * @page: %gint, load this page + * * @n: %gint, load this many pages + * * @autorotate: %gboolean, use orientation tag to rotate the image + * during load + * + * Exactly as vips_tiffload(), but read from a stream. + * + * See also: vips_tiffload(). + * + * Returns: 0 on success, -1 on error. + */ +int +vips_tiffload_stream( VipsStreamInput *input, VipsImage **out, ... ) +{ + va_list ap; + int result; + + va_start( ap, out ); + result = vips_call_split( "tiffload_stream", ap, input, out ); + va_end( ap ); + + return( result ); +} diff --git a/libvips/foreign/vips2tiff.c b/libvips/foreign/vips2tiff.c index fca3d64e..8ce2598d 100644 --- a/libvips/foreign/vips2tiff.c +++ b/libvips/foreign/vips2tiff.c @@ -1713,6 +1713,7 @@ wtiff_gather( Wtiff *wtiff ) wtiff->layer->below ) for( layer = wtiff->layer->below; layer; layer = layer->below ) { + VipsStreamInput *input; TIFF *in; #ifdef DEBUG @@ -1720,15 +1721,23 @@ wtiff_gather( Wtiff *wtiff ) #endif /*DEBUG*/ if( layer->lname ) { - if( !(in = vips__tiff_openin( layer->lname )) ) + if( !(input = + vips_stream_input_new_from_filename( + layer->lname )) ) return( -1 ); } else { - if( !(in = vips__tiff_openin_buffer( wtiff->im, - layer->buf, layer->len )) ) + if( !(input = vips_stream_input_new_from_memory( + layer->buf, layer->len )) ) return( -1 ); } + if( !(in = vips__tiff_openin_stream( input )) ) { + VIPS_UNREF( input ); + return( -1 ); + } + VIPS_UNREF( input ); + if( wtiff_copy_tiff( wtiff, wtiff->layer->tif, in ) ) { TIFFClose( in ); return( -1 ); diff --git a/libvips/include/vips/foreign.h b/libvips/include/vips/foreign.h index ece753c6..180585ff 100644 --- a/libvips/include/vips/foreign.h +++ b/libvips/include/vips/foreign.h @@ -481,6 +481,8 @@ int vips_tiffload( const char *filename, VipsImage **out, ... ) __attribute__((sentinel)); int vips_tiffload_buffer( void *buf, size_t len, VipsImage **out, ... ) __attribute__((sentinel)); +int vips_tiffload_stream( VipsStreamInput *input, VipsImage **out, ... ) + __attribute__((sentinel)); int vips_tiffsave( VipsImage *in, const char *filename, ... ) __attribute__((sentinel)); int vips_tiffsave_buffer( VipsImage *in, void **buf, size_t *len, ... )