From bb75535151a849b244cf9b1168b842e2db859516 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Sat, 8 Jun 2019 16:47:40 +0100 Subject: [PATCH] much faster ismagick We used to Ping files to see if IM would load them, but this can be extremely slow for file formats like ARW. Instead, use GetImageMagick() ... it just checks the magic number. --- ChangeLog | 1 + libvips/foreign/magick.c | 12 ++++++++++ libvips/foreign/magick.h | 2 ++ libvips/foreign/magick7load.c | 45 +++++++---------------------------- libvips/foreign/magickload.c | 29 ++++++++-------------- 5 files changed, 33 insertions(+), 56 deletions(-) diff --git a/ChangeLog b/ChangeLog index c1a05d31..0fc484d3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,7 @@ - fix memleak in tiff pyr save to memory [scossu] - istiff attempts to read the first directory rather than just testing the magic number [przemyslawpluta] +- much faster ismagick() [jcupitt] 21/9/18 started 8.8.0 - much faster smartcrop [lovell] diff --git a/libvips/foreign/magick.c b/libvips/foreign/magick.c index 5119b7ed..367a4ba5 100644 --- a/libvips/foreign/magick.c +++ b/libvips/foreign/magick.c @@ -641,4 +641,16 @@ magick_set_magick_profile( Image *image, return( 0 ); } +/* Does a few bytes look like a file IM can handle? + */ +gboolean +magick_ismagick( const unsigned char *buf, size_t length ) +{ + char format[MagickPathExtent]; + + magick_genesis(); + + return( GetImageMagick( buf, length, format ) ); +} + #endif /*HAVE_MAGICK*/ diff --git a/libvips/foreign/magick.h b/libvips/foreign/magick.h index 8993a31e..9c9be67d 100644 --- a/libvips/foreign/magick.h +++ b/libvips/foreign/magick.h @@ -84,4 +84,6 @@ int magick_set_vips_profile( VipsImage *im, Image *image ); int magick_set_magick_profile( Image *image, VipsImage *im, ExceptionInfo *exception ); +gboolean magick_ismagick( const unsigned char *buf, size_t length ); + #endif /*HAVE_MAGICK6*/ diff --git a/libvips/foreign/magick7load.c b/libvips/foreign/magick7load.c index 6592ff74..5c0ceb76 100644 --- a/libvips/foreign/magick7load.c +++ b/libvips/foreign/magick7load.c @@ -757,26 +757,15 @@ G_DEFINE_TYPE( VipsForeignLoadMagick7File, vips_foreign_load_magick7_file, static gboolean ismagick7( const char *filename ) { - Image *image; - ImageInfo *image_info; - ExceptionInfo *exception; - int result; - - magick_genesis(); - - /* Horribly slow :-( + /* Fetch the first 100 bytes. Hopefully that'll be enough. */ - image_info = CloneImageInfo( NULL ); - exception = magick_acquire_exception(); - 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 ); - VIPS_FREEF( DestroyImageInfo, image_info ); - VIPS_FREEF( magick_destroy_exception, exception ); + unsigned char buf[100]; - return( result ); + /* Files shorter than 100 bytes will leave nonsense at the end of buf, + * but it shouldn't matter. + */ + return( vips__get_bytes( filename, buf, 100 ) && + magick_ismagick( buf, 100 ) ); } static int @@ -860,25 +849,7 @@ G_DEFINE_TYPE( VipsForeignLoadMagick7Buffer, vips_foreign_load_magick7_buffer, static gboolean vips_foreign_load_magick7_buffer_is_a_buffer( const void *buf, size_t len ) { - Image *image; - ImageInfo *image_info; - ExceptionInfo *exception; - int result; - - magick_genesis(); - - /* Horribly slow :-( - */ - image_info = CloneImageInfo( NULL ); - exception = magick_acquire_exception(); - magick_sniff_bytes( image_info, buf, len ); - image = PingBlob( image_info, buf, len, exception ); - result = image != NULL; - VIPS_FREEF( DestroyImageList, image ); - VIPS_FREEF( DestroyImageInfo, image_info ); - VIPS_FREEF( magick_destroy_exception, exception ); - - return( result ); + return( magick_ismagick( (const unsigned char *) buf, len ) ); } static int diff --git a/libvips/foreign/magickload.c b/libvips/foreign/magickload.c index 9643805e..a1215a30 100644 --- a/libvips/foreign/magickload.c +++ b/libvips/foreign/magickload.c @@ -63,6 +63,7 @@ #ifdef HAVE_MAGICK6 #include "pforeign.h" +#include "magick.h" typedef struct _VipsForeignLoadMagick { VipsForeignLoad parent_object; @@ -172,16 +173,15 @@ G_DEFINE_TYPE( VipsForeignLoadMagickFile, vips_foreign_load_magick_file, static gboolean ismagick( const char *filename ) { - VipsImage *t; - int result; + /* Fetch the first 100 bytes. Hopefully that'll be enough. + */ + unsigned char buf[100]; - t = vips_image_new(); - vips_error_freeze(); - result = vips__magick_read_header( filename, t, NULL, 0, 1 ); - g_object_unref( t ); - vips_error_thaw(); - - return( result == 0 ); + /* Files shorter than 100 bytes will leave nonsense at the end of buf, + * but it shouldn't matter. + */ + return( vips__get_bytes( filename, buf, 100 ) && + magick_ismagick( buf, 100 ) ); } /* Unfortunately, libMagick does not support header-only reads very well. See @@ -258,16 +258,7 @@ G_DEFINE_TYPE( VipsForeignLoadMagickBuffer, vips_foreign_load_magick_buffer, static gboolean vips_foreign_load_magick_buffer_is_a_buffer( const void *buf, size_t len ) { - VipsImage *t; - int result; - - t = vips_image_new(); - vips_error_freeze(); - result = vips__magick_read_buffer_header( buf, len, t, NULL, 0, 1 ); - g_object_unref( t ); - vips_error_thaw(); - - return( result == 0 ); + return( magick_ismagick( (const unsigned char *) buf, len ) ); } /* Unfortunately, libMagick does not support header-only reads very well. See