add minimise support to VipsStreamInput

This commit is contained in:
John Cupitt 2019-10-14 10:46:17 +01:00
parent 6f0002c023
commit c01c3b9100
4 changed files with 91 additions and 60 deletions

View File

@ -335,6 +335,12 @@ readjpeg_close_cb( VipsObject *object, ReadJpeg *jpeg )
(void) readjpeg_free( jpeg ); (void) readjpeg_free( jpeg );
} }
static void
vips_stream_input_minimise_cb( VipsImage *image, VipsStreamInput *input )
{
vips_stream_input_minimise( input );
}
static ReadJpeg * static ReadJpeg *
readjpeg_new( VipsStreamInput *input, VipsImage *out, readjpeg_new( VipsStreamInput *input, VipsImage *out,
int shrink, gboolean fail, gboolean autorotate ) int shrink, gboolean fail, gboolean autorotate )
@ -370,6 +376,8 @@ readjpeg_new( VipsStreamInput *input, VipsImage *out,
g_signal_connect( out, "close", g_signal_connect( out, "close",
G_CALLBACK( readjpeg_close_cb ), jpeg ); G_CALLBACK( readjpeg_close_cb ), jpeg );
g_signal_connect( out, "minimise",
G_CALLBACK( vips_stream_input_minimise_cb ), input );
return( jpeg ); return( jpeg );
} }
@ -777,11 +785,6 @@ read_jpeg_generate( VipsRegion *or,
return( -1 ); return( -1 );
} }
/* We may have been minimised.
*/
if( readjpeg_open_input( jpeg ) )
return( -1 );
/* If --fail is set, we make read fail on any warnings. This /* If --fail is set, we make read fail on any warnings. This
* will stop on any errors from the previous jpeg_read_scanlines(). * will stop on any errors from the previous jpeg_read_scanlines().
* libjpeg warnings are used for serious image corruption, like * libjpeg warnings are used for serious image corruption, like
@ -946,6 +949,8 @@ vips__jpeg_read( ReadJpeg *jpeg, VipsImage *out, gboolean header_only )
*/ */
vips_autorot_remove_angle( out ); vips_autorot_remove_angle( out );
} }
vips_stream_input_minimise( jpeg->input );
} }
else { else {
if( read_jpeg_image( jpeg, out ) ) if( read_jpeg_image( jpeg, out ) )

View File

@ -122,10 +122,10 @@ typedef struct _VipsStreamInput {
*/ */
gboolean decode; gboolean decode;
/* TRUE is this input source supports rewind. If not, then we save data /* TRUE is this descriptor supports lseek(). If not, then we save data
* read during header phase in a buffer. * read during header phase in a buffer.
*/ */
gboolean rewindable; gboolean seekable;
/*< private >*/ /*< private >*/
@ -183,8 +183,7 @@ VipsStreamInput *vips_stream_input_new_from_options( const char *options );
ssize_t vips_stream_input_read( VipsStreamInput *input, ssize_t vips_stream_input_read( VipsStreamInput *input,
unsigned char *data, size_t length ); unsigned char *data, size_t length );
int vips_stream_input_rewind( VipsStreamInput *input ); int vips_stream_input_rewind( VipsStreamInput *input );
void vips_stream_minimise( VipsStreamInput *input ); void vips_stream_input_minimise( VipsStreamInput *input );
void vips_stream_set_image( VipsStreamInput *input, VipsImage *image );
void vips_stream_input_decode( VipsStreamInput *input ); void vips_stream_input_decode( VipsStreamInput *input );
gboolean vips_stream_input_eof( VipsStreamInput *input ); gboolean vips_stream_input_eof( VipsStreamInput *input );
unsigned char *vips_stream_input_sniff( VipsStreamInput *input, size_t length ); unsigned char *vips_stream_input_sniff( VipsStreamInput *input, size_t length );

View File

@ -121,16 +121,8 @@ G_DEFINE_ABSTRACT_TYPE( VipsStream, vips_stream, VIPS_TYPE_OBJECT );
VIPS_OBJECT( STREAM )->nickname) VIPS_OBJECT( STREAM )->nickname)
static void static void
vips_stream_finalize( GObject *gobject ) vips_stream_close( VipsStream *stream )
{ {
VipsStream *stream = (VipsStream *) gobject;
#ifdef VIPS_DEBUG
VIPS_DEBUG_MSG( "vips_stream_finalize: " );
vips_object_print_name( VIPS_OBJECT( gobject ) );
VIPS_DEBUG_MSG( "\n" );
#endif /*VIPS_DEBUG*/
if( stream->close_descriptor >= 0 ) { if( stream->close_descriptor >= 0 ) {
close( stream->close_descriptor ); close( stream->close_descriptor );
stream->close_descriptor = -1; stream->close_descriptor = -1;
@ -141,6 +133,21 @@ vips_stream_finalize( GObject *gobject )
stream->tracked_descriptor = -1; stream->tracked_descriptor = -1;
} }
stream->descriptor = -1;
}
static void
vips_stream_finalize( GObject *gobject )
{
VipsStream *stream = (VipsStream *) gobject;
#ifdef VIPS_DEBUG
VIPS_DEBUG_MSG( "vips_stream_finalize: " );
vips_object_print_name( VIPS_OBJECT( gobject ) );
VIPS_DEBUG_MSG( "\n" );
#endif /*VIPS_DEBUG*/
vips_stream_close( stream );
VIPS_FREE( stream->filename ); VIPS_FREE( stream->filename );
G_OBJECT_CLASS( vips_stream_parent_class )->finalize( gobject ); G_OBJECT_CLASS( vips_stream_parent_class )->finalize( gobject );
@ -192,6 +199,41 @@ vips_stream_input_finalize( GObject *gobject )
G_OBJECT_CLASS( vips_stream_input_parent_class )->finalize( gobject ); G_OBJECT_CLASS( vips_stream_input_parent_class )->finalize( gobject );
} }
static int
vips_stream_input_open( VipsStreamInput *input )
{
VipsStream *stream = VIPS_STREAM( input );
if( stream->descriptor == -1 &&
stream->tracked_descriptor == -1 &&
stream->filename ) {
int fd;
off_t new_pos;
if( (fd = vips_tracked_open( stream->filename,
MODE_READ )) == -1 ) {
vips_error_system( errno, STREAM_NAME( stream ),
"%s", _( "unable to open for read" ) );
return( -1 );
}
stream->tracked_descriptor = fd;
stream->descriptor = fd;
input->seekable = TRUE;
VIPS_DEBUG_MSG( "vips_stream_input_open: "
"restoring read position %zd\n", input->read_position );
new_pos = lseek( stream->descriptor, 0, SEEK_SET );
if( new_pos == -1 ) {
vips_error_system( errno, STREAM_NAME( stream ),
"%s", _( "unable to lseek()" ) );
return( 0 );
}
}
return( 0 );
}
static int static int
vips_stream_input_build( VipsObject *object ) vips_stream_input_build( VipsObject *object )
{ {
@ -211,20 +253,9 @@ vips_stream_input_build( VipsObject *object )
return( -1 ); return( -1 );
} }
if( vips_object_argument_isset( object, "filename" ) ) { if( vips_object_argument_isset( object, "filename" ) &&
int fd; vips_stream_input_open( input ) )
return( -1 );
if( (fd = vips_tracked_open( stream->filename,
MODE_READ )) == -1 ) {
vips_error_system( errno, STREAM_NAME( stream ),
"%s", _( "unable to open for read" ) );
return( -1 );
}
stream->tracked_descriptor = fd;
stream->descriptor = fd;
input->rewindable = TRUE;
}
if( vips_object_argument_isset( object, "descriptor" ) ) { if( vips_object_argument_isset( object, "descriptor" ) ) {
stream->descriptor = dup( stream->descriptor ); stream->descriptor = dup( stream->descriptor );
@ -232,11 +263,11 @@ vips_stream_input_build( VipsObject *object )
} }
if( vips_object_argument_isset( object, "blob" ) ) if( vips_object_argument_isset( object, "blob" ) )
input->rewindable = TRUE; input->seekable = TRUE;
/* Need to save the header if the source is not rewindable. /* Need to save the header if the source is not seekable.
*/ */
if( !input->rewindable ) if( !input->seekable )
input->header_bytes = g_byte_array_new(); input->header_bytes = g_byte_array_new();
/* We always want a sniff buffer. /* We always want a sniff buffer.
@ -254,6 +285,11 @@ vips_stream_input_read_real( VipsStreamInput *input,
VIPS_DEBUG_MSG( "vips_stream_input_read_real:\n" ); VIPS_DEBUG_MSG( "vips_stream_input_read_real:\n" );
/* Make sure we are open, in case we've been minimised.
*/
if( vips_stream_input_open( input ) )
return( -1 );
if( input->blob ) { if( input->blob ) {
VipsArea *area = (VipsArea *) input->blob; VipsArea *area = (VipsArea *) input->blob;
ssize_t available = VIPS_MIN( length, ssize_t available = VIPS_MIN( length,
@ -288,7 +324,7 @@ vips_stream_input_rewind_real( VipsStreamInput *input )
return( -1 ); return( -1 );
} }
if( input->rewindable && if( input->seekable &&
stream->descriptor != -1 ) { stream->descriptor != -1 ) {
off_t new_pos; off_t new_pos;
@ -312,7 +348,12 @@ vips_stream_input_rewind_real( VipsStreamInput *input )
static void static void
vips_stream_input_minimise_real( VipsStreamInput *input ) vips_stream_input_minimise_real( VipsStreamInput *input )
{ {
VIPS_DEBUG_MSG( "vips_stream_minimise_real:\n" ); VipsStream *stream = VIPS_STREAM( input );
if( stream->filename &&
stream->descriptor != -1 &&
input->seekable )
vips_stream_close( stream );
} }
static void static void
@ -341,11 +382,11 @@ vips_stream_input_class_init( VipsStreamInputClass *class )
G_STRUCT_OFFSET( VipsStreamInput, blob ), G_STRUCT_OFFSET( VipsStreamInput, blob ),
VIPS_TYPE_BLOB ); VIPS_TYPE_BLOB );
VIPS_ARG_BOOL( class, "rewindable", 4, VIPS_ARG_BOOL( class, "seekable", 4,
_( "rewindable" ), _( "Seekable" ),
_( "'descriptor' supports rewind" ), _( "'descriptor' supports lseek()" ),
VIPS_ARGUMENT_OPTIONAL_INPUT, VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsStreamInput, rewindable ), G_STRUCT_OFFSET( VipsStreamInput, seekable ),
FALSE ); FALSE );
} }
@ -544,11 +585,11 @@ vips_stream_input_read( VipsStreamInput *input,
if( n == 0 ) if( n == 0 )
input->eof = TRUE; input->eof = TRUE;
/* If we're not rewindable, we need to save header bytes for /* If we're not seekable, we need to save header bytes for
* reuse. * reuse.
*/ */
if( input->header_bytes && if( input->header_bytes &&
!input->rewindable && !input->seekable &&
!input->decode && !input->decode &&
n > 0 ) n > 0 )
g_byte_array_append( input->header_bytes, g_byte_array_append( input->header_bytes,
@ -603,19 +644,6 @@ vips_stream_input_decode( VipsStreamInput *input )
} }
} }
static void
vips_stream_input_minimise_cb( VipsImage *image, VipsStreamInput *input )
{
vips_stream_input_minimise( input );
}
void
vips_stream_input_set_image( VipsStreamInput *input, VipsImage *image )
{
g_signal_connect( image, "minimise",
G_CALLBACK( vips_stream_input_minimise_cb ), input );
}
/** /**
* vips_stream_input_sniff: * vips_stream_input_sniff:
* @bytes: number of bytes to sniff * @bytes: number of bytes to sniff

View File

@ -7,10 +7,9 @@ set -e
. ./variables.sh . ./variables.sh
# reenable when we have minise support ini stream if test_supported jpegload; then
# if test_supported jpegload; then ./test_descriptors $image
# ./test_descriptors $image fi
# fi
if test_supported heifload; then if test_supported heifload; then
./test_descriptors $test_images/Example1.heic ./test_descriptors $test_images/Example1.heic