From 8d5af9fe8ac7192dae92bac077e96ecbec14ee8f Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Mon, 4 Feb 2019 17:54:57 +0000 Subject: [PATCH] add xmp/ipct/icc etc. to magickload ImageMagick supports binary metadata with `ResetImageProfileIterator()` etc. Implementing support gives us xmp / ipct / icc support, plus perhaps some others. --- ChangeLog | 1 + configure.ac | 10 ++++++++++ libvips/foreign/magick2vips.c | 34 +++++++++++++++++++++++++++++++++- libvips/foreign/magick7load.c | 30 +++++++++++++++++++++++++++++- 4 files changed, 73 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 00ad7950..37295272 100644 --- a/ChangeLog +++ b/ChangeLog @@ -20,6 +20,7 @@ - fix race in temp filename creation [lhecker] - add @reduction_effort param to webpsave [lovell] - add @option_string param to thumbnail_buffer [kleisauke] +- add XMP, IPCT, ICC etc. to magickload 4/1/19 started 8.7.4 - magickload with magick6 API did not chain exceptions correctly causing a diff --git a/configure.ac b/configure.ac index acfd0066..3ef1c2b5 100644 --- a/configure.ac +++ b/configure.ac @@ -700,6 +700,16 @@ if test x"$magick6" = x"yes"; then LIBS="$save_LIBS" fi +if test x"$magick6" = x"yes"; then + # GM does not have ResetImageProfileIterator + save_LIBS="$LIBS" + LIBS="$LIBS $MAGICK_LIBS" + AC_CHECK_FUNCS(ResetImageProfileIterator, + AC_DEFINE(HAVE_RESETIMAGEPROFILEITERATOR,1, + [define if your magick has ResetImageProfileIterator.])) + LIBS="$save_LIBS" +fi + if test x"$magick6" = x"yes"; then # more recent magicks have GetVirtualPixels rather than GetImagePixels save_LIBS="$LIBS" diff --git a/libvips/foreign/magick2vips.c b/libvips/foreign/magick2vips.c index c6777546..daa2473e 100644 --- a/libvips/foreign/magick2vips.c +++ b/libvips/foreign/magick2vips.c @@ -62,6 +62,8 @@ * 4/1/19 kleisauke * - we did not chain exceptions correctly, causing a memory leak * - added wrapper funcs for exception handling + * 4/2/19 + * - add profile (xmp, ipct, etc.) read */ /* @@ -421,8 +423,38 @@ parse_header( Read *read ) vips_image_pipelinev( im, VIPS_DEMAND_STYLE_SMALLTILE, NULL ); - /* Three ways to loop over attributes / properties :-( +#ifdef HAVE_RESETIMAGEPROFILEITERATOR +{ + /* "Profiles" are things like icc profiles, xmp, iptc, etc. and are + * stored as blobs, since they may contain embedded \0. */ + char *key; + + ResetImageProfileIterator( image ); + while( (key = GetNextImageProfile( image )) ) { + char name_text[256]; + VipsBuf name = VIPS_BUF_STATIC( name_text ); + const StringInfo *profile; + void *data; + size_t length; + + if( strcmp( key, "xmp" ) == 0 ) + vips_buf_appendf( &name, VIPS_META_XMP_NAME ); + else if( strcmp( key, "iptc" ) == 0 ) + vips_buf_appendf( &name, VIPS_META_IPTC_NAME ); + else if( strcmp( key, "icc" ) == 0 ) + vips_buf_appendf( &name, VIPS_META_ICC_NAME ); + else + vips_buf_appendf( &name, "magickprofile-%s", key ); + + profile = GetImageProfile( image, key ); + data = GetStringInfoDatum( profile ); + length = GetStringInfoLength( profile ); + vips_image_set_blob_copy( im, vips_buf_all( &name ), + data, length ); + } +} +#endif /*HAVE_RESETIMAGEPROFILEITERATOR*/ #ifdef HAVE_RESETIMAGEPROPERTYITERATOR { diff --git a/libvips/foreign/magick7load.c b/libvips/foreign/magick7load.c index e9eab634..91ad8629 100644 --- a/libvips/foreign/magick7load.c +++ b/libvips/foreign/magick7load.c @@ -6,6 +6,8 @@ * - add @n, deprecate @all_frames (just sets n = -1) * 24/7/18 * - sniff extra filetypes + * 4/2/19 + * - add profile (xmp, ipct, etc.) read */ /* @@ -527,7 +529,7 @@ vips_foreign_load_magick7_parse( VipsForeignLoadMagick7 *magick7, vips_image_pipelinev( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL ); - /* Get all the metadata. + /* Get all the string metadata. */ ResetImagePropertyIterator( image ); while( (key = GetNextImageProperty( image )) ) { @@ -544,6 +546,32 @@ vips_foreign_load_magick7_parse( VipsForeignLoadMagick7 *magick7, vips_image_set_string( out, vips_buf_all( &name ), value ); } + /* All the binary metadata. + */ + ResetImageProfileIterator( image ); + while( (key = GetNextImageProfile( image )) ) { + char name_text[256]; + VipsBuf name = VIPS_BUF_STATIC( name_text ); + const StringInfo *profile; + void *data; + size_t length; + + if( strcmp( key, "xmp" ) == 0 ) + vips_buf_appendf( &name, VIPS_META_XMP_NAME ); + else if( strcmp( key, "iptc" ) == 0 ) + vips_buf_appendf( &name, VIPS_META_IPTC_NAME ); + else if( strcmp( key, "icc" ) == 0 ) + vips_buf_appendf( &name, VIPS_META_ICC_NAME ); + else + vips_buf_appendf( &name, "magickprofile-%s", key ); + + profile = GetImageProfile( image, key ); + data = GetStringInfoDatum( profile ); + length = GetStringInfoLength( profile ); + vips_image_set_blob_copy( out, vips_buf_all( &name ), + data, length ); + } + magick7->n_pages = GetImageListLength( GetFirstImageInList( image ) ); #ifdef DEBUG printf( "image has %d pages\n", magick7->n_pages );