diff --git a/libvips/foreign/jpegload.c b/libvips/foreign/jpegload.c index 9e53914e..bc0e2559 100644 --- a/libvips/foreign/jpegload.c +++ b/libvips/foreign/jpegload.c @@ -169,14 +169,6 @@ typedef VipsForeignLoadJpegClass VipsForeignLoadJpegFileClass; G_DEFINE_TYPE( VipsForeignLoadJpegFile, vips_foreign_load_jpeg_file, vips_foreign_load_jpeg_get_type() ); -static VipsForeignFlags -vips_foreign_load_jpeg_file_get_flags_filename( const char *filename ) -{ - /* The jpeg reader supports sequential read. - */ - return( VIPS_FOREIGN_SEQUENTIAL ); -} - static gboolean vips_foreign_load_jpeg_file_is_a( const char *filename ) { @@ -232,8 +224,6 @@ vips_foreign_load_jpeg_file_class_init( VipsForeignLoadJpegFileClass *class ) */ foreign_class->priority = 50; - load_class->get_flags_filename = - vips_foreign_load_jpeg_file_get_flags_filename; 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; diff --git a/libvips/foreign/pforeign.h b/libvips/foreign/pforeign.h index 26804bee..796c1d38 100644 --- a/libvips/foreign/pforeign.h +++ b/libvips/foreign/pforeign.h @@ -183,6 +183,7 @@ int vips__png_read( const char *name, VipsImage *out, gboolean readbehind ); gboolean vips__png_ispng_buffer( const void *buf, size_t len ); int vips__png_ispng( const char *filename ); gboolean vips__png_isinterlaced( const char *filename ); +gboolean vips__png_isinterlaced_buffer( const void *buffer, size_t length ); extern const char *vips__png_suffs[]; int vips__png_read_buffer( const void *buffer, size_t length, VipsImage *out, gboolean readbehind ); diff --git a/libvips/foreign/pngload.c b/libvips/foreign/pngload.c index 7f2f8fc0..f2bb9328 100644 --- a/libvips/foreign/pngload.c +++ b/libvips/foreign/pngload.c @@ -167,12 +167,29 @@ typedef VipsForeignLoadClass VipsForeignLoadPngBufferClass; G_DEFINE_TYPE( VipsForeignLoadPngBuffer, vips_foreign_load_png_buffer, VIPS_TYPE_FOREIGN_LOAD ); +static VipsForeignFlags +vips_foreign_load_png_buffer_get_flags( VipsForeignLoad *load ) +{ + VipsForeignLoadPngBuffer *buffer = (VipsForeignLoadPngBuffer *) load; + + VipsForeignFlags flags; + + flags = 0; + if( vips__png_isinterlaced_buffer( buffer->buf->data, + buffer->buf->length ) ) + flags |= VIPS_FOREIGN_PARTIAL; + else + flags |= VIPS_FOREIGN_SEQUENTIAL; + + return( flags ); +} + static int vips_foreign_load_png_buffer_header( VipsForeignLoad *load ) { - VipsForeignLoadPngBuffer *png = (VipsForeignLoadPngBuffer *) load; + VipsForeignLoadPngBuffer *buffer = (VipsForeignLoadPngBuffer *) load; - if( vips__png_header_buffer( png->buf->data, png->buf->length, + if( vips__png_header_buffer( buffer->buf->data, buffer->buf->length, load->out ) ) return( -1 ); @@ -182,9 +199,9 @@ vips_foreign_load_png_buffer_header( VipsForeignLoad *load ) static int vips_foreign_load_png_buffer_load( VipsForeignLoad *load ) { - VipsForeignLoadPngBuffer *png = (VipsForeignLoadPngBuffer *) load; + VipsForeignLoadPngBuffer *buffer = (VipsForeignLoadPngBuffer *) load; - if( vips__png_read_buffer( png->buf->data, png->buf->length, + if( vips__png_read_buffer( buffer->buf->data, buffer->buf->length, load->real, load->access == VIPS_ACCESS_SEQUENTIAL ) ) return( -1 ); @@ -218,7 +235,7 @@ vips_foreign_load_png_buffer_class_init( VipsForeignLoadPngBufferClass *class ) } static void -vips_foreign_load_png_buffer_init( VipsForeignLoadPngBuffer *png ) +vips_foreign_load_png_buffer_init( VipsForeignLoadPngBuffer *buffer ) { } diff --git a/libvips/foreign/vipspng.c b/libvips/foreign/vipspng.c index cbd6b23f..46324377 100644 --- a/libvips/foreign/vipspng.c +++ b/libvips/foreign/vipspng.c @@ -710,6 +710,28 @@ vips__png_read_buffer( const void *buffer, size_t length, VipsImage *out, return( 0 ); } +/* Interlaced PNGs need to be entirely decompressed into memory then can be + * served partially from there. Non-interlaced PNGs may be read sequentially. + */ +gboolean +vips__png_isinterlaced_buffer( const void *buffer, size_t length ) +{ + VipsImage *image; + Read *read; + int interlace_type; + + image = vips_image_new(); + + if( !(read = read_new_buffer( image, buffer, length, FALSE )) ) { + g_object_unref( image ); + return( -1 ); + } + interlace_type = png_get_interlace_type( read->pPng, read->pInfo ); + g_object_unref( image ); + + return( interlace_type != PNG_INTERLACE_NONE ); +} + const char *vips__png_suffs[] = { ".png", NULL }; /* What we track during a PNG write.