From e89dac20bb7826fb2b5539d3b4d8bd0ee2b5feba Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 24 Jul 2018 17:38:36 +0100 Subject: [PATCH] add sniffing framework to magickload though it only spots ICO for now see https://github.com/jcupitt/pyvips/issues/39 --- ChangeLog | 1 + libvips/foreign/magick.c | 43 +++++++++++++++++++++++++++++++++++ libvips/foreign/magick.h | 3 +++ libvips/foreign/magick2vips.c | 30 +++++++++++++----------- libvips/foreign/magick7load.c | 16 ++++++------- 5 files changed, 72 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index e8cce361..cde234b1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -35,6 +35,7 @@ - paste in the test suite from pyvips - get EXIF tag names from tag plus ifd [@Nan619] - escape ASCII control characters in XML +- magickload now sniffs some file types itself 12/3/18 started 8.6.4 - better fitting of fonts with overhanging edges [AdriĆ ] diff --git a/libvips/foreign/magick.c b/libvips/foreign/magick.c index 95799734..3516e420 100644 --- a/libvips/foreign/magick.c +++ b/libvips/foreign/magick.c @@ -1,6 +1,9 @@ /* Common functions for interfacing with ImageMagick. * * 22/12/17 dlemstra + * + * 24/7/18 + * - add the sniffer */ /* @@ -238,6 +241,46 @@ magick_set_image_option( ImageInfo *image_info, #endif /*HAVE_SETIMAGEOPTION*/ } +/* ImageMagick can't detect some formats, like ICO, by examining the contents -- + * ico.c simply does not have a recogniser. + * + * For these formats, do the detection ourselves. + * + * Set image_info->magick if we spot one of the things we can spot. + */ +static const char * +magick_sniff( const unsigned char *bytes, size_t length ) +{ + if( length >= 4 && + bytes[0] == 0 && + bytes[1] == 0 && + bytes[2] == 1 && + bytes[3] == 0 ) + return( "ICO" ); + + return( NULL ); +} + +void +magick_sniff_bytes( ImageInfo *image_info, + const unsigned char *bytes, size_t length ) +{ + const char *format; + + if( (format = magick_sniff( bytes, length )) ) + vips_strncpy( image_info->magick, format, MaxTextExtent ); +} + +void +magick_sniff_file( ImageInfo *image_info, const char *filename ) +{ + unsigned char bytes[256]; + size_t length; + + if( (length = vips__get_bytes( filename, bytes, 256 )) >= 4 ) + magick_sniff_bytes( image_info, bytes, 256 ); +} + void magick_vips_error( const char *domain, ExceptionInfo *exception ) { diff --git a/libvips/foreign/magick.h b/libvips/foreign/magick.h index 1d7539f5..e95ea5f2 100644 --- a/libvips/foreign/magick.h +++ b/libvips/foreign/magick.h @@ -59,6 +59,9 @@ void magick_set_number_scenes( ImageInfo *image_info, int scene, int number_scenes ); void magick_inherit_exception( ExceptionInfo *exception, Image *image ); +void magick_sniff_bytes( ImageInfo *image_info, + const unsigned char *bytes, size_t length ); +void magick_sniff_file( ImageInfo *image_info, const char *filename ); void magick_vips_error( const char *domain, ExceptionInfo *exception ); void magick_genesis( void ); diff --git a/libvips/foreign/magick2vips.c b/libvips/foreign/magick2vips.c index 1e082b2f..8c22c6c7 100644 --- a/libvips/foreign/magick2vips.c +++ b/libvips/foreign/magick2vips.c @@ -57,6 +57,8 @@ * - try using GetImageChannelDepth() instead of ->depth * 25/5/18 * - don't use Ping, it's too unreliable + * 24/7/18 + * - sniff extra filetypes */ /* @@ -128,6 +130,8 @@ typedef struct _Read { char *filename; VipsImage *im; + const void *buf; + size_t len; int page; int n; @@ -182,7 +186,8 @@ read_close( VipsImage *im, Read *read ) static Read * read_new( const char *filename, VipsImage *im, - const char *density, int page, int n ) + const void *buf, const size_t len, + const char *density, int page, int n ) { Read *read; @@ -197,6 +202,8 @@ read_new( const char *filename, VipsImage *im, if( !(read = VIPS_NEW( im, Read )) ) return( NULL ); read->filename = filename ? g_strdup( filename ) : NULL; + read->buf = buf; + read->len = len; read->page = page; read->n = n; read->im = im; @@ -218,15 +225,12 @@ read_new( const char *filename, VipsImage *im, vips_strncpy( read->image_info->filename, filename, MaxTextExtent ); - /* The file format hint, eg. "ICO". - * - if( format ) - vips_strncpy( read->image_info->magick, - format, MaxTextExtent ); - * + /* Any extra file format detection. */ - printf( "magick2vips: insert format stuff here\n" ); - + if( filename ) + magick_sniff_file( read->image_info, filename ); + if( buf ) + magick_sniff_bytes( read->image_info, buf, len ); /* Canvas resolution for rendering vector formats like SVG. */ @@ -754,7 +758,7 @@ vips__magick_read( const char *filename, printf( "magick2vips: vips__magick_read: %s\n", filename ); #endif /*DEBUG*/ - if( !(read = read_new( filename, out, density, page, n )) ) + if( !(read = read_new( filename, out, NULL, n, density, page, n )) ) return( -1 ); #ifdef DEBUG @@ -788,7 +792,7 @@ vips__magick_read_header( const char *filename, printf( "vips__magick_read_header: %s\n", filename ); #endif /*DEBUG*/ - if( !(read = read_new( filename, out, density, page, n )) ) + if( !(read = read_new( filename, out, NULL, 0, density, page, n )) ) return( -1 ); #ifdef DEBUG @@ -833,7 +837,7 @@ vips__magick_read_buffer( const void *buf, const size_t len, printf( "magick2vips: vips__magick_read_buffer: %p %zu\n", buf, len ); #endif /*DEBUG*/ - if( !(read = read_new( NULL, out, density, page, n )) ) + if( !(read = read_new( NULL, out, buf, len, density, page, n )) ) return( -1 ); #ifdef DEBUG @@ -867,7 +871,7 @@ vips__magick_read_buffer_header( const void *buf, const size_t len, printf( "vips__magick_read_buffer_header: %p %zu\n", buf, len ); #endif /*DEBUG*/ - if( !(read = read_new( NULL, out, density, page, n )) ) + if( !(read = read_new( NULL, out, buf, len, density, page, n )) ) return( -1 ); #ifdef DEBUG diff --git a/libvips/foreign/magick7load.c b/libvips/foreign/magick7load.c index 85fdbeeb..95f518a7 100644 --- a/libvips/foreign/magick7load.c +++ b/libvips/foreign/magick7load.c @@ -4,6 +4,8 @@ * - from magickload * 25/11/16 * - add @n, deprecate @all_frames (just sets n = -1) + * 24/7/18 + * - sniff extra filetypes */ /* @@ -305,14 +307,6 @@ vips_foreign_load_magick7_build( VipsObject *object ) if( magick7->all_frames ) magick7->n = -1; - /* The file format hint, eg. "ICO". - * - if( magick7->format ) - vips_strncpy( magick7->image_info->magick, - magick7->format, MaxTextExtent ); - * - */ - /* Canvas resolution for rendering vector formats like SVG. */ VIPS_SETSTR( magick7->image_info->density, magick7->density ); @@ -768,6 +762,7 @@ ismagick7( const char *filename ) image_info = CloneImageInfo( NULL ); exception = AcquireExceptionInfo(); vips_strncpy( image_info->filename, filename, MagickPathExtent ); + magick_sniff_file( image_info, filename ); image = PingImage( image_info, exception ); result = image != NULL; VIPS_FREEF( DestroyImageList, image ); @@ -790,6 +785,8 @@ vips_foreign_load_magick7_file_header( VipsForeignLoad *load ) vips_strncpy( magick7->image_info->filename, file->filename, MagickPathExtent ); + magick_sniff_file( magick7->image_info, file->filename ); + /* It would be great if we could PingImage and just read the header, * but sadly many IM coders do not support ping. The critical one for * us is DICOM. @@ -867,6 +864,7 @@ vips_foreign_load_magick7_buffer_is_a_buffer( const void *buf, size_t len ) */ image_info = CloneImageInfo( NULL ); exception = AcquireExceptionInfo(); + magick_sniff_bytes( image_info, buf, len ); image = PingBlob( image_info, buf, len, exception ); result = image != NULL; VIPS_FREEF( DestroyImageList, image ); @@ -893,6 +891,8 @@ vips_foreign_load_magick7_buffer_header( VipsForeignLoad *load ) * * We have to read the whole image in _header. */ + magick_sniff_bytes( magick7->image_info, + magick7_buffer->buf->data, magick7_buffer->buf->length ); magick7->image = BlobToImage( magick7->image_info, magick7_buffer->buf->data, magick7_buffer->buf->length, magick7->exception );