diff --git a/libvips/deprecated/im_jpeg2vips.c b/libvips/deprecated/im_jpeg2vips.c index 8b00fd79..1824f7a2 100644 --- a/libvips/deprecated/im_jpeg2vips.c +++ b/libvips/deprecated/im_jpeg2vips.c @@ -111,9 +111,18 @@ jpeg2vips( const char *name, IMAGE *out, gboolean header_only ) } #ifdef HAVE_JPEG - if( vips__jpeg_read_file( filename, out, - header_only, shrink, fail_on_warn, FALSE ) ) +{ + VipsStreamInput *input; + + if( !(input = vips_stream_input_new_from_filename( filename )) ) return( -1 ); + if( vips__jpeg_read_stream( input, out, + header_only, shrink, fail_on_warn, FALSE ) ) { + VIPS_UNREF( input ); + return( -1 ); + } + VIPS_UNREF( input ); +} #else vips_error( "im_jpeg2vips", "%s", _( "no JPEG support in your libvips" ) ); diff --git a/libvips/foreign/jpeg2vips.c b/libvips/foreign/jpeg2vips.c index 8cd0fd43..bbf15587 100644 --- a/libvips/foreign/jpeg2vips.c +++ b/libvips/foreign/jpeg2vips.c @@ -169,10 +169,6 @@ typedef struct _ReadJpeg { */ gboolean fail; - /* Used for file input only. - */ - char *filename; - struct jpeg_decompress_struct cinfo; ErrorManager eman; gboolean invert_pels; @@ -193,113 +189,12 @@ typedef struct _ReadJpeg { int output_width; int output_height; - /* If we close and reopen, save the ftell point here. - */ - long seek_position; - - /* The memory area we read from. - */ - const void *buf; - size_t len; - /* The stream we read from. */ VipsStreamInput *input; } ReadJpeg; -/* Private struct for memory input. - */ -typedef struct { - /* Public jpeg fields. - */ - struct jpeg_source_mgr pub; - - /* Private stuff during read. - */ - const JOCTET *buf; - size_t len; -} InputBuffer; - -static void -init_source( j_decompress_ptr cinfo ) -{ -} - -/* - * Fill the input buffer --- called whenever buffer is emptied. - * - * We fill the buffer on readjpeg_buffer(), so this will only be called if - * libjpeg tries to read beyond the buffer. - */ -static boolean -fill_input_buffer( j_decompress_ptr cinfo ) -{ - static const JOCTET eoi_buffer[4] = { - (JOCTET) 0xFF, (JOCTET) JPEG_EOI, 0, 0 - }; - - InputBuffer *src = (InputBuffer *) cinfo->src; - - WARNMS( cinfo, JWRN_JPEG_EOF ); - src->pub.next_input_byte = eoi_buffer; - src->pub.bytes_in_buffer = 2; - - return( TRUE ); -} - -/* - * Skip data --- used to skip over a potentially large amount of - * uninteresting data (such as an APPn marker). - * - * Writers of suspendable-input applications must note that skip_input_data - * is not granted the right to give a suspension return. If the skip extends - * beyond the data currently in the buffer, the buffer can be marked empty so - * that the next read will cause a fill_input_buffer call that can suspend. - * Arranging for additional bytes to be discarded before reloading the input - * buffer is the application writer's problem. - */ -static void -skip_input_data( j_decompress_ptr cinfo, long num_bytes ) -{ - InputBuffer *src = (InputBuffer *) cinfo->src; - - if( num_bytes > 0 ) { - while (num_bytes > (long) src->pub.bytes_in_buffer) { - num_bytes -= (long) src->pub.bytes_in_buffer; - (void) (*src->pub.fill_input_buffer) (cinfo); - - /* note we assume that fill_input_buffer will never - * return FALSE, so suspension need not be handled. - */ - } - - src->pub.next_input_byte += (size_t) num_bytes; - src->pub.bytes_in_buffer -= (size_t) num_bytes; - } -} - -/* - * An additional method that can be provided by data source modules is the - * resync_to_restart method for error recovery in the presence of RST markers. - * For the moment, this source module just uses the default resync method - * provided by the JPEG library. That method assumes that no backtracking - * is possible. - */ - -/* - * Terminate source --- called by jpeg_finish_decompress - * after all data has been read. Often a no-op. - * - * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding - * application must deal with any cleanup that should happen even - * for error exit. - */ -static void -term_source( j_decompress_ptr cinfo ) -{ -} - #define STREAM_BUFFER_SIZE (4096) /* Private struct for stream input. @@ -314,18 +209,18 @@ typedef struct { VipsStreamInput *input; unsigned char buf[STREAM_BUFFER_SIZE]; -} InputSource; +} Source; static void stream_init_source( j_decompress_ptr cinfo ) { - InputSource *source = (InputSource *) cinfo->src; + Source *src = (Source *) cinfo->src; /* Start off empty ... libjpeg will call fill_input_buffer to get the * first bytes. */ - source->pub.next_input_byte = source->buf; - source->pub.bytes_in_buffer = 0; + src->pub.next_input_byte = src->buf; + src->pub.bytes_in_buffer = 0; } /* Fill the input buffer --- called whenever buffer is emptied. @@ -337,19 +232,19 @@ stream_fill_input_buffer( j_decompress_ptr cinfo ) (JOCTET) 0xFF, (JOCTET) JPEG_EOI, 0, 0 }; - InputSource *source = (InputSource *) cinfo->src; + Source *src = (Source *) cinfo->src; size_t read; - if( (read = vips_stream_input_read( source->input, - source->buf, STREAM_BUFFER_SIZE )) == -1 ) { - WARNMS( cinfo, JWRN_JPEG_EOF ); - source->pub.next_input_byte = eoi_buffer; - source->pub.bytes_in_buffer = 2; + if( (read = vips_stream_input_read( src->input, + src->buf, STREAM_BUFFER_SIZE )) > 0 ) { + src->pub.next_input_byte = src->buf; + src->pub.bytes_in_buffer = read; } else { - source->pub.next_input_byte = source->buf; - source->pub.bytes_in_buffer = read; + WARNMS( cinfo, JWRN_JPEG_EOF ); + src->pub.next_input_byte = eoi_buffer; + src->pub.bytes_in_buffer = 2; } return( TRUE ); @@ -360,41 +255,9 @@ readjpeg_open_input( ReadJpeg *jpeg ) { j_decompress_ptr cinfo = &jpeg->cinfo; - if( jpeg->filename && - !jpeg->eman.fp ) { - if( !(jpeg->eman.fp = - vips__file_open_read( jpeg->filename, NULL, FALSE )) ) - return( -1 ); - jpeg_stdio_src( cinfo, jpeg->eman.fp ); - if( jpeg->seek_position != -1 ) - fseek( jpeg->eman.fp, jpeg->seek_position, SEEK_SET ); - } - - if( jpeg->buf && - !cinfo->src ) { - InputBuffer *src; - - cinfo->src = (struct jpeg_source_mgr *) - (*cinfo->mem->alloc_small)( - (j_common_ptr) cinfo, JPOOL_PERMANENT, - sizeof( InputBuffer ) ); - - src = (InputBuffer *) cinfo->src; - src->buf = jpeg->buf; - src->len = jpeg->len; - - src->pub.init_source = init_source; - src->pub.fill_input_buffer = fill_input_buffer; - src->pub.skip_input_data = skip_input_data; - src->pub.resync_to_restart = jpeg_resync_to_restart; - src->pub.term_source = term_source; - src->pub.bytes_in_buffer = jpeg->len; - src->pub.next_input_byte = jpeg->buf; - } - if( jpeg->input && !cinfo->src ) { - InputSource *src; + Source *src; if( vips_stream_input_rewind( jpeg->input ) ) return( -1 ); @@ -402,15 +265,13 @@ readjpeg_open_input( ReadJpeg *jpeg ) cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)( (j_common_ptr) cinfo, JPOOL_PERMANENT, - sizeof( InputSource ) ); + sizeof( Source ) ); - src = (InputSource *) cinfo->src; + src = (Source *) cinfo->src; src->input = jpeg->input; src->pub.init_source = stream_init_source; src->pub.fill_input_buffer = stream_fill_input_buffer; - src->pub.skip_input_data = skip_input_data; src->pub.resync_to_restart = jpeg_resync_to_restart; - src->pub.term_source = term_source; src->pub.bytes_in_buffer = 0; src->pub.next_input_byte = src->buf; } @@ -418,21 +279,6 @@ readjpeg_open_input( ReadJpeg *jpeg ) return( 0 ); } -/* This can be called many times. - */ -static void -readjpeg_close_input( ReadJpeg *jpeg ) -{ -#ifdef DEBUG - printf( "readjpeg_close_input:\n" ); -#endif /*DEBUG*/ - - if( jpeg->eman.fp ) { - jpeg->seek_position = ftell( jpeg->eman.fp ); - VIPS_FREEF( fclose, jpeg->eman.fp ); - } -} - /* This can be called many times. */ static int @@ -448,8 +294,6 @@ readjpeg_free( ReadJpeg *jpeg ) jpeg->eman.pub.num_warnings = 0; } - readjpeg_close_input( jpeg ); - /* Don't call jpeg_finish_decompress(). It just checks the tail of the * file and who cares about that. All mem is freed in * jpeg_destroy_decompress(). @@ -459,7 +303,7 @@ readjpeg_free( ReadJpeg *jpeg ) */ jpeg_destroy_decompress( &jpeg->cinfo ); - VIPS_FREE( jpeg->filename ); + VIPS_UNREF( jpeg->input ); return( 0 ); } @@ -470,34 +314,25 @@ readjpeg_close_cb( VipsObject *object, ReadJpeg *jpeg ) (void) readjpeg_free( jpeg ); } -static void -readjpeg_minimise_cb( VipsObject *object, ReadJpeg *jpeg ) -{ -#ifdef DEBUG - printf( "readjpeg_minimise_cb:\n" ); -#endif /*DEBUG*/ - - readjpeg_close_input( jpeg ); -} - static ReadJpeg * -readjpeg_new( VipsImage *out, int shrink, gboolean fail, gboolean autorotate ) +readjpeg_new( VipsStreamInput *input, VipsImage *out, + int shrink, gboolean fail, gboolean autorotate ) { ReadJpeg *jpeg; if( !(jpeg = VIPS_NEW( out, ReadJpeg )) ) return( NULL ); + jpeg->input = input; + g_object_ref( input ); jpeg->shrink = shrink; jpeg->fail = fail; - jpeg->filename = NULL; jpeg->cinfo.err = jpeg_std_error( &jpeg->eman.pub ); jpeg->eman.pub.error_exit = vips__new_error_exit; jpeg->eman.pub.output_message = vips__new_output_message; jpeg->eman.fp = NULL; jpeg->y_pos = 0; jpeg->autorotate = autorotate; - jpeg->seek_position = -1; /* This is used by the error handlers to signal invalidate on the * output image. @@ -514,24 +349,10 @@ readjpeg_new( VipsImage *out, int shrink, gboolean fail, gboolean autorotate ) g_signal_connect( out, "close", G_CALLBACK( readjpeg_close_cb ), jpeg ); - g_signal_connect( out, "minimise", - G_CALLBACK( readjpeg_minimise_cb ), jpeg ); return( jpeg ); } -/* Set input to a file. - */ -static int -readjpeg_file( ReadJpeg *jpeg, const char *filename ) -{ - jpeg->filename = g_strdup( filename ); - if( readjpeg_open_input( jpeg ) ) - return( -1 ); - - return( 0 ); -} - static const char * find_chroma_subsample( struct jpeg_decompress_struct *cinfo ) { @@ -974,11 +795,6 @@ read_jpeg_generate( VipsRegion *or, jpeg->y_pos += 1; } - /* Shut down the input early if we can. - */ - if( jpeg->y_pos >= or->im->Ysize ) - readjpeg_close_input( jpeg ); - VIPS_GATE_STOP( "read_jpeg_generate: work" ); return( 0 ); @@ -1063,8 +879,6 @@ read_jpeg_image( ReadJpeg *jpeg, VipsImage *out ) return( 0 ); } -/* Read the jpeg from file or buffer. - */ static int vips__jpeg_read( ReadJpeg *jpeg, VipsImage *out, gboolean header_only ) { @@ -1120,103 +934,18 @@ vips__jpeg_read( ReadJpeg *jpeg, VipsImage *out, gboolean header_only ) return( 0 ); } -/* Read a JPEG file into a VIPS image. - */ -int -vips__jpeg_read_file( const char *filename, VipsImage *out, - gboolean header_only, int shrink, gboolean fail, - gboolean autorotate ) -{ - ReadJpeg *jpeg; - - if( !(jpeg = readjpeg_new( out, shrink, fail, autorotate )) ) - return( -1 ); - - /* Here for longjmp() from vips__new_error_exit() during startup. - */ - if( setjmp( jpeg->eman.jmp ) ) - return( -1 ); - - /* Set input to file. - */ - if( readjpeg_file( jpeg, filename ) ) - return( -1 ); - - if( vips__jpeg_read( jpeg, out, header_only ) ) - return( -1 ); - - VIPS_SETSTR( out->filename, filename ); - - /* We can kill off the decompress early if this is just a header read. - * This saves an fd during read. - */ - if( header_only ) - readjpeg_free( jpeg ); - - return( 0 ); -} - -int -vips__jpeg_read_buffer( const void *buf, size_t len, VipsImage *out, - gboolean header_only, int shrink, int fail, gboolean autorotate ) -{ - ReadJpeg *jpeg; - - if( !(jpeg = readjpeg_new( out, shrink, fail, autorotate )) ) - return( -1 ); - - if( setjmp( jpeg->eman.jmp ) ) - return( -1 ); - - jpeg->buf = buf; - jpeg->len = len; - if( readjpeg_open_input( jpeg ) ) - return( -1 ); - - if( vips__jpeg_read( jpeg, out, header_only ) ) - return( -1 ); - - return( 0 ); -} - -int -vips__isjpeg_buffer( const void *buf, size_t len ) -{ - const guchar *str = (const guchar *) buf; - - if( len >= 2 && - str[0] == 0xff && - str[1] == 0xd8 ) - return( 1 ); - - return( 0 ); -} - -int -vips__isjpeg( const char *filename ) -{ - unsigned char buf[2]; - - if( vips__get_bytes( filename, buf, 2 ) == 2 && - vips__isjpeg_buffer( buf, 2 ) ) - return( 1 ); - - return( 0 ); -} - int vips__jpeg_read_stream( VipsStreamInput *input, VipsImage *out, gboolean header_only, int shrink, int fail, gboolean autorotate ) { ReadJpeg *jpeg; - if( !(jpeg = readjpeg_new( out, shrink, fail, autorotate )) ) + if( !(jpeg = readjpeg_new( input, out, shrink, fail, autorotate )) ) return( -1 ); if( setjmp( jpeg->eman.jmp ) ) return( -1 ); - jpeg->input = input; if( readjpeg_open_input( jpeg ) ) return( -1 ); @@ -1232,7 +961,8 @@ vips__isjpeg_stream( VipsStreamInput *input ) const unsigned char *p; if( (p = vips_stream_input_sniff( input, 2 )) && - vips__isjpeg_buffer( p, 2 ) ) + p[0] == 0xff && + p[1] == 0xd8 ) return( 1 ); return( 0 ); diff --git a/libvips/foreign/jpegload.c b/libvips/foreign/jpegload.c index cfe7e4a4..2960950c 100644 --- a/libvips/foreign/jpegload.c +++ b/libvips/foreign/jpegload.c @@ -155,171 +155,9 @@ vips_foreign_load_jpeg_init( VipsForeignLoadJpeg *jpeg ) jpeg->shrink = 1; } -typedef struct _VipsForeignLoadJpegFile { - VipsForeignLoadJpeg parent_object; - - /* Filename for load. - */ - char *filename; - -} VipsForeignLoadJpegFile; - -typedef VipsForeignLoadJpegClass VipsForeignLoadJpegFileClass; - -G_DEFINE_TYPE( VipsForeignLoadJpegFile, vips_foreign_load_jpeg_file, - vips_foreign_load_jpeg_get_type() ); - -static gboolean -vips_foreign_load_jpeg_file_is_a( const char *filename ) -{ - return( vips__isjpeg( filename ) ); -} - -static int -vips_foreign_load_jpeg_file_header( VipsForeignLoad *load ) -{ - VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load; - VipsForeignLoadJpegFile *file = (VipsForeignLoadJpegFile *) load; - - if( vips__jpeg_read_file( file->filename, load->out, - TRUE, jpeg->shrink, load->fail, jpeg->autorotate ) ) - return( -1 ); - - return( 0 ); -} - -static int -vips_foreign_load_jpeg_file_load( VipsForeignLoad *load ) -{ - VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load; - VipsForeignLoadJpegFile *file = (VipsForeignLoadJpegFile *) load; - - if( vips__jpeg_read_file( file->filename, load->real, - FALSE, jpeg->shrink, load->fail, jpeg->autorotate ) ) - return( -1 ); - - return( 0 ); -} - -static void -vips_foreign_load_jpeg_file_class_init( VipsForeignLoadJpegFileClass *class ) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS( class ); - VipsObjectClass *object_class = (VipsObjectClass *) class; - VipsForeignClass *foreign_class = (VipsForeignClass *) 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 = "jpegload"; - object_class->description = _( "load jpeg from file" ); - - foreign_class->suffs = vips__jpeg_suffs; - - /* We are fast at is_a(), so high priority. - */ - foreign_class->priority = 50; - - load_class->is_a = vips_foreign_load_jpeg_file_is_a; - load_class->header = vips_foreign_load_jpeg_file_header; - load_class->load = vips_foreign_load_jpeg_file_load; - - VIPS_ARG_STRING( class, "filename", 1, - _( "Filename" ), - _( "Filename to load from" ), - VIPS_ARGUMENT_REQUIRED_INPUT, - G_STRUCT_OFFSET( VipsForeignLoadJpegFile, filename ), - NULL ); -} - -static void -vips_foreign_load_jpeg_file_init( VipsForeignLoadJpegFile *file ) -{ -} - -typedef struct _VipsForeignLoadJpegBuffer { - VipsForeignLoadJpeg parent_object; - - /* Load from a buffer. - */ - VipsArea *buf; - -} VipsForeignLoadJpegBuffer; - -typedef VipsForeignLoadJpegClass VipsForeignLoadJpegBufferClass; - -G_DEFINE_TYPE( VipsForeignLoadJpegBuffer, vips_foreign_load_jpeg_buffer, - vips_foreign_load_jpeg_get_type() ); - -static int -vips_foreign_load_jpeg_buffer_header( VipsForeignLoad *load ) -{ - VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load; - VipsForeignLoadJpegBuffer *buffer = (VipsForeignLoadJpegBuffer *) load; - - if( vips__jpeg_read_buffer( buffer->buf->data, buffer->buf->length, - load->out, TRUE, jpeg->shrink, load->fail, jpeg->autorotate ) ) - return( -1 ); - - return( 0 ); -} - -static int -vips_foreign_load_jpeg_buffer_load( VipsForeignLoad *load ) -{ - VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load; - VipsForeignLoadJpegBuffer *buffer = (VipsForeignLoadJpegBuffer *) load; - - if( vips__jpeg_read_buffer( buffer->buf->data, buffer->buf->length, - load->real, FALSE, jpeg->shrink, load->fail, jpeg->autorotate ) ) - return( -1 ); - - return( 0 ); -} - -static gboolean -vips_foreign_load_jpeg_buffer_is_a( const void *buf, size_t len ) -{ - return( vips__isjpeg_buffer( buf, len ) ); -} - -static void -vips_foreign_load_jpeg_buffer_class_init( - VipsForeignLoadJpegBufferClass *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 = "jpegload_buffer"; - object_class->description = _( "load jpeg from buffer" ); - - load_class->is_a_buffer = vips_foreign_load_jpeg_buffer_is_a; - load_class->header = vips_foreign_load_jpeg_buffer_header; - load_class->load = vips_foreign_load_jpeg_buffer_load; - - VIPS_ARG_BOXED( class, "buffer", 1, - _( "Buffer" ), - _( "Buffer to load from" ), - VIPS_ARGUMENT_REQUIRED_INPUT, - G_STRUCT_OFFSET( VipsForeignLoadJpegBuffer, buf ), - VIPS_TYPE_BLOB ); -} - -static void -vips_foreign_load_jpeg_buffer_init( VipsForeignLoadJpegBuffer *buffer ) -{ -} - typedef struct _VipsForeignLoadJpegStream { VipsForeignLoadJpeg parent_object; - /* Load from a buffer. - */ VipsStreamInput *input; } VipsForeignLoadJpegStream; @@ -395,6 +233,206 @@ vips_foreign_load_jpeg_stream_init( VipsForeignLoadJpegStream *stream ) { } +typedef struct _VipsForeignLoadJpegFile { + VipsForeignLoadJpeg parent_object; + + char *filename; + +} VipsForeignLoadJpegFile; + +typedef VipsForeignLoadJpegClass VipsForeignLoadJpegFileClass; + +G_DEFINE_TYPE( VipsForeignLoadJpegFile, vips_foreign_load_jpeg_file, + vips_foreign_load_jpeg_get_type() ); + +static gboolean +vips_foreign_load_jpeg_file_is_a( const char *filename ) +{ + VipsStreamInput *input; + gboolean result; + + if( !(input = vips_stream_input_new_from_filename( filename )) ) + return( FALSE ); + result = vips__isjpeg_stream( input ); + VIPS_UNREF( input ); + + return( result ); +} + +static int +vips_foreign_load_jpeg_file_header( VipsForeignLoad *load ) +{ + VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load; + VipsForeignLoadJpegFile *file = (VipsForeignLoadJpegFile *) load; + + VipsStreamInput *input; + + if( !(input = vips_stream_input_new_from_filename( file->filename )) ) + return( -1 ); + if( vips__jpeg_read_stream( input, load->out, + TRUE, jpeg->shrink, load->fail, jpeg->autorotate ) ) { + VIPS_UNREF( input ); + return( -1 ); + } + VIPS_UNREF( input ); + + return( 0 ); +} + +static int +vips_foreign_load_jpeg_file_load( VipsForeignLoad *load ) +{ + VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load; + VipsForeignLoadJpegFile *file = (VipsForeignLoadJpegFile *) load; + + VipsStreamInput *input; + + if( !(input = vips_stream_input_new_from_filename( file->filename )) ) + return( -1 ); + if( vips__jpeg_read_stream( input, load->real, + FALSE, jpeg->shrink, load->fail, jpeg->autorotate ) ) { + VIPS_UNREF( input ); + return( -1 ); + } + VIPS_UNREF( input ); + + return( 0 ); +} + +static void +vips_foreign_load_jpeg_file_class_init( VipsForeignLoadJpegFileClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignClass *foreign_class = (VipsForeignClass *) 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 = "jpegload"; + object_class->description = _( "load jpeg from file" ); + + foreign_class->suffs = vips__jpeg_suffs; + + /* We are fast at is_a(), so high priority. + */ + foreign_class->priority = 50; + + load_class->is_a = vips_foreign_load_jpeg_file_is_a; + load_class->header = vips_foreign_load_jpeg_file_header; + load_class->load = vips_foreign_load_jpeg_file_load; + + VIPS_ARG_STRING( class, "filename", 1, + _( "Filename" ), + _( "Filename to load from" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsForeignLoadJpegFile, filename ), + NULL ); +} + +static void +vips_foreign_load_jpeg_file_init( VipsForeignLoadJpegFile *file ) +{ +} + +typedef struct _VipsForeignLoadJpegBuffer { + VipsForeignLoadJpeg parent_object; + + VipsBlob *blob; + +} VipsForeignLoadJpegBuffer; + +typedef VipsForeignLoadJpegClass VipsForeignLoadJpegBufferClass; + +G_DEFINE_TYPE( VipsForeignLoadJpegBuffer, vips_foreign_load_jpeg_buffer, + vips_foreign_load_jpeg_get_type() ); + +static gboolean +vips_foreign_load_jpeg_buffer_is_a( const void *buf, size_t len ) +{ + VipsStreamInput *input; + gboolean result; + + if( !(input = vips_stream_input_new_from_memory( buf, len )) ) + return( FALSE ); + result = vips__isjpeg_stream( input ); + VIPS_UNREF( input ); + + return( result ); +} + +static int +vips_foreign_load_jpeg_buffer_header( VipsForeignLoad *load ) +{ + VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load; + VipsForeignLoadJpegBuffer *buffer = (VipsForeignLoadJpegBuffer *) load; + + VipsStreamInput *input; + + if( !(input = vips_stream_input_new_from_blob( buffer->blob )) ) + return( -1 ); + if( vips__jpeg_read_stream( input, load->out, + TRUE, jpeg->shrink, load->fail, jpeg->autorotate ) ) { + VIPS_UNREF( input ); + return( -1 ); + } + VIPS_UNREF( input ); + + return( 0 ); +} + +static int +vips_foreign_load_jpeg_buffer_load( VipsForeignLoad *load ) +{ + VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load; + VipsForeignLoadJpegBuffer *buffer = (VipsForeignLoadJpegBuffer *) load; + + VipsStreamInput *input; + + if( !(input = vips_stream_input_new_from_blob( buffer->blob )) ) + return( -1 ); + if( vips__jpeg_read_stream( input, load->real, + FALSE, jpeg->shrink, load->fail, jpeg->autorotate ) ) { + VIPS_UNREF( input ); + return( -1 ); + } + VIPS_UNREF( input ); + + return( 0 ); +} + +static void +vips_foreign_load_jpeg_buffer_class_init( + VipsForeignLoadJpegBufferClass *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 = "jpegload_buffer"; + object_class->description = _( "load jpeg from buffer" ); + + load_class->is_a_buffer = vips_foreign_load_jpeg_buffer_is_a; + load_class->header = vips_foreign_load_jpeg_buffer_header; + load_class->load = vips_foreign_load_jpeg_buffer_load; + + VIPS_ARG_BOXED( class, "buffer", 1, + _( "Buffer" ), + _( "Buffer to load from" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsForeignLoadJpegBuffer, blob ), + VIPS_TYPE_BLOB ); +} + +static void +vips_foreign_load_jpeg_buffer_init( VipsForeignLoadJpegBuffer *buffer ) +{ +} + #endif /*HAVE_JPEG*/ /** diff --git a/libvips/foreign/pforeign.h b/libvips/foreign/pforeign.h index 234fa0bd..85940c89 100644 --- a/libvips/foreign/pforeign.h +++ b/libvips/foreign/pforeign.h @@ -185,13 +185,6 @@ int vips__jpeg_write_buffer( VipsImage *in, gboolean overshoot_deringing, gboolean optimize_scans, int quant_table ); -int vips__isjpeg_buffer( const void *buf, size_t len ); -int vips__isjpeg( const char *filename ); -int vips__jpeg_read_file( const char *name, VipsImage *out, - gboolean header_only, int shrink, gboolean fail, gboolean autorotate ); -int vips__jpeg_read_buffer( const void *buf, size_t len, VipsImage *out, - gboolean header_only, int shrink, int fail, gboolean autorotate ); - int vips__jpeg_read_stream( VipsStreamInput *input, VipsImage *out, gboolean header_only, int shrink, int fail, gboolean autorotate ); int vips__isjpeg_stream( VipsStreamInput *input ); diff --git a/libvips/include/vips/stream.h b/libvips/include/vips/stream.h index c2b17bc3..a6b73d10 100644 --- a/libvips/include/vips/stream.h +++ b/libvips/include/vips/stream.h @@ -169,7 +169,8 @@ GType vips_stream_input_get_type( void ); VipsStreamInput *vips_stream_input_new_from_descriptor( int descriptor ); VipsStreamInput *vips_stream_input_new_from_filename( const char *filename ); VipsStreamInput *vips_stream_input_new_from_blob( VipsBlob *blob ); -VipsStreamInput *vips_stream_input_new_from_memory( void *data, size_t size ); +VipsStreamInput *vips_stream_input_new_from_memory( const void *data, + size_t size ); ssize_t vips_stream_input_read( VipsStreamInput *input, unsigned char *buffer, size_t length ); @@ -217,8 +218,8 @@ typedef struct _VipsStreamOutputClass { GType vips_stream_output_get_type( void ); -VipsStreamOutput *vips_stream_output_new_to_descriptor( int descriptor ); -VipsStreamOutput *vips_stream_output_new_to_filename( const char *filename ); +VipsStreamOutput *vips_stream_output_new_from_descriptor( int descriptor ); +VipsStreamOutput *vips_stream_output_new_from_filename( const char *filename ); int vips_stream_output_write( VipsStreamOutput *stream, const unsigned char *buffer, size_t buffer_size ); diff --git a/libvips/iofuncs/stream.c b/libvips/iofuncs/stream.c index 76dacc7a..45b2f14a 100644 --- a/libvips/iofuncs/stream.c +++ b/libvips/iofuncs/stream.c @@ -253,7 +253,7 @@ vips_stream_input_read_real( VipsStreamInput *input, if( available <= 0 ) return( 0 ); - memcpy( buffer, area->data, available ); + memcpy( buffer, area->data + input->read_position, available ); return( available ); } @@ -448,7 +448,7 @@ vips_stream_input_new_from_blob( VipsBlob *blob ) * Returns: a new #VipsStream */ VipsStreamInput * -vips_stream_input_new_from_memory( void *data, size_t size ) +vips_stream_input_new_from_memory( const void *data, size_t size ) { VipsStreamInput *stream; VipsBlob *blob; diff --git a/test/test-suite/test_colour.py b/test/test-suite/test_colour.py index 4e15fae8..f441bb79 100644 --- a/test/test-suite/test_colour.py +++ b/test/test-suite/test_colour.py @@ -83,7 +83,6 @@ class TestColour: assert_almost_equal_objects(before, after, threshold=10) - # test results from Bruce Lindbloom's calculator: # http://www.brucelindbloom.com def test_dE00(self):