]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/property.c
(no commit message)
[imagemagick] / MagickCore / property.c
index a6bd55dca9a56c3b74545745a539bd67640fc371..284ae1a391c4e174bc12a98de1e73c3c879a88b3 100644 (file)
 %                         MagickCore Property Methods                         %
 %                                                                             %
 %                              Software Design                                %
-%                                John Cristy                                  %
+%                                   Cristy                                    %
 %                                 March 2000                                  %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization      %
 %  dedicated to making software imaging solutions freely available.           %
 %                                                                             %
 %  You may not use this file except in compliance with the License.  You may  %
@@ -36,7 +36,8 @@
 %
 %
 */
-\f
+
+
 /*
   Include declarations.
 */
@@ -44,6 +45,7 @@
 #include "MagickCore/artifact.h"
 #include "MagickCore/attribute.h"
 #include "MagickCore/cache.h"
+#include "MagickCore/cache-private.h"
 #include "MagickCore/color.h"
 #include "MagickCore/color-private.h"
 #include "MagickCore/colorspace-private.h"
 #include "MagickCore/version.h"
 #include "MagickCore/xml-tree.h"
 #include "MagickCore/xml-tree-private.h"
+#if defined(MAGICKCORE_LCMS_DELEGATE)
+#if defined(MAGICKCORE_HAVE_LCMS_LCMS2_H)
+#include <lcms/lcms2.h>
+#elif defined(MAGICKCORE_HAVE_LCMS2_H)
+#include "lcms2.h"
+#elif defined(MAGICKCORE_HAVE_LCMS_LCMS_H)
+#include <lcms/lcms.h>
+#else
+#include "lcms.h"
+#endif
+#endif
+\f
+/*
+  Define declarations.
+*/
+#if defined(MAGICKCORE_LCMS_DELEGATE)
+#if defined(LCMS_VERSION) && (LCMS_VERSION < 2000)
+#define cmsUInt32Number  DWORD
+#endif
+#endif
 \f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -147,6 +169,7 @@ MagickExport MagickBooleanType CloneImageProperties(Image *image,
   image->extract_info=clone_image->extract_info;
   image->filter=clone_image->filter;
   image->fuzz=clone_image->fuzz;
+  image->intensity=clone_image->intensity;
   image->interlace=clone_image->interlace;
   image->interpolate=clone_image->interpolate;
   image->endian=clone_image->endian;
@@ -537,7 +560,7 @@ static inline unsigned short ReadPropertyMSBShort(const unsigned char **p,
     value;
 
   if (*length < 2)
-    return((unsigned short) ~0U);
+    return((unsigned short) ~0);
   for (i=0; i < 2; i++)
   {
     c=(int) (*(*p)++);
@@ -1530,6 +1553,63 @@ static MagickBooleanType GetEXIFProperty(const Image *image,
   return(status);
 }
 
+static MagickBooleanType GetICCProperty(const Image *image,const char *property,
+  ExceptionInfo *exception)
+{
+  const StringInfo
+    *profile;
+
+  magick_unreferenced(property);
+
+  profile=GetImageProfile(image,"icc");
+  if (profile == (StringInfo *) NULL)
+    profile=GetImageProfile(image,"icm");
+  if (profile == (StringInfo *) NULL)
+    return(MagickFalse);
+  if (GetStringInfoLength(profile) < 128)
+    return(MagickFalse);  /* minimum ICC profile length */
+#if defined(MAGICKCORE_LCMS_DELEGATE)
+  {
+    cmsHPROFILE
+      icc_profile;
+
+    icc_profile=cmsOpenProfileFromMem(GetStringInfoDatum(profile),
+      (cmsUInt32Number) GetStringInfoLength(profile));
+    if (icc_profile != (cmsHPROFILE *) NULL)
+      {
+#if defined(LCMS_VERSION) && (LCMS_VERSION < 2000)
+        const char
+          *name;
+
+        name=cmsTakeProductName(icc_profile);
+        if (name != (const char *) NULL)
+          (void) SetImageProperty((Image *) image,"icc:name",name,exception);
+#else
+        char
+          info[MaxTextExtent];
+
+        (void) cmsGetProfileInfoASCII(icc_profile,cmsInfoDescription,
+          "en","US",info,MaxTextExtent);
+        (void) SetImageProperty((Image *) image,"icc:description",info,
+          exception);
+        (void) cmsGetProfileInfoASCII(icc_profile,cmsInfoManufacturer,
+          "en","US",info,MaxTextExtent);
+        (void) SetImageProperty((Image *) image,"icc:manufacturer",info,
+          exception);
+        (void) cmsGetProfileInfoASCII(icc_profile,cmsInfoModel,"en",
+          "US",info,MaxTextExtent);
+        (void) SetImageProperty((Image *) image,"icc:model",info,exception);
+        (void) cmsGetProfileInfoASCII(icc_profile,cmsInfoCopyright,
+          "en","US",info,MaxTextExtent);
+        (void) SetImageProperty((Image *) image,"icc:copyright",info,exception);
+#endif
+        (void) cmsCloseProfile(icc_profile);
+      }
+  }
+#endif
+  return(MagickTrue);
+}
+
 static MagickBooleanType GetXMPProperty(const Image *image,const char *property)
 {
   char
@@ -1917,9 +1997,9 @@ static char *TraceSVGClippath(const unsigned char *blob,size_t length,
           point[i].x=(double) x*columns/4096/4096;
           point[i].y=(double) y*rows/4096/4096;
         }
-        if( IfMagickFalse(in_subpath) )
+        if (in_subpath == MagickFalse)
           {
-            (void) FormatLocaleString(message,MaxTextExtent,"M %g,%g\n",
+            (void) FormatLocaleString(message,MaxTextExtent,"M %g %g\n",
               point[1].x,point[1].y);
             for (i=0; i < 3; i++)
             {
@@ -1929,14 +2009,28 @@ static char *TraceSVGClippath(const unsigned char *blob,size_t length,
           }
         else
           {
+            /*
+              Handle special cases when Bezier curves are used to describe
+              corners and straight lines.
+            */
             if ((last[1].x == last[2].x) && (last[1].y == last[2].y) &&
                 (point[0].x == point[1].x) && (point[0].y == point[1].y))
-              (void) FormatLocaleString(message,MaxTextExtent,"L %g,%g\n",
-                point[1].x,point[1].y);
-            else
               (void) FormatLocaleString(message,MaxTextExtent,
-                "C %g,%g %g,%g %g,%g\n",last[2].x,last[2].y,
-                point[0].x,point[0].y,point[1].x,point[1].y);
+                "L %g %g\n",point[1].x,point[1].y);
+            else
+              if ((last[1].x == last[2].x) && (last[1].y == last[2].y))
+                (void) FormatLocaleString(message,MaxTextExtent,
+                  "V %g %g %g %g\n",point[0].x,point[0].y,
+                  point[1].x,point[1].y);
+              else
+                if ((point[0].x == point[1].x) && (point[0].y == point[1].y))
+                  (void) FormatLocaleString(message,MaxTextExtent,
+                    "Y %g %g %g %g\n",last[2].x,last[2].y,
+                    point[1].x,point[1].y);
+                else
+                  (void) FormatLocaleString(message,MaxTextExtent,
+                    "C %g %g %g %g %g %g\n",last[2].x,
+                    last[2].y,point[0].x,point[0].y,point[1].x,point[1].y);
             for (i=0; i < 3; i++)
               last[i]=point[i];
           }
@@ -1948,17 +2042,29 @@ static char *TraceSVGClippath(const unsigned char *blob,size_t length,
         */
         if (knot_count == 0)
           {
+           /*
+              Same special handling as above except we compare to the
+              first point in the path and close the path.
+            */
             if ((last[1].x == last[2].x) && (last[1].y == last[2].y) &&
                 (first[0].x == first[1].x) && (first[0].y == first[1].y))
               (void) FormatLocaleString(message,MaxTextExtent,
-                "L %g,%g Z\n",first[1].x,first[1].y);
+                "L %g %g Z\n",first[1].x,first[1].y);
             else
-              {
+              if ((last[1].x == last[2].x) && (last[1].y == last[2].y))
                 (void) FormatLocaleString(message,MaxTextExtent,
-                  "C %g,%g %g,%g %g,%g Z\n",last[2].x,
-                  last[2].y,first[0].x,first[0].y,first[1].x,first[1].y);
-                (void) ConcatenateString(&path,message);
-              }
+                  "V %g %g %g %g Z\n",first[0].x,first[0].y,
+                  first[1].x,first[1].y);
+              else
+                if ((first[0].x == first[1].x) && (first[0].y == first[1].y))
+                  (void) FormatLocaleString(message,MaxTextExtent,
+                    "Y %g %g %g %g Z\n",last[2].x,last[2].y,
+                    first[1].x,first[1].y);
+                else
+                  (void) FormatLocaleString(message,MaxTextExtent,
+                    "C %g %g %g %g %g %g Z\n",last[2].x,
+                    last[2].y,first[0].x,first[0].y,first[1].x,first[1].y);
+            (void) ConcatenateString(&path,message);
             in_subpath=MagickFalse;
           }
         break;
@@ -1995,11 +2101,9 @@ MagickExport const char *GetImageProperty(const Image *image,
 
   assert(image != (Image *) NULL);
   assert(image->signature == MagickSignature);
-  if( IfMagickTrue(image->debug) )
+  if (IfMagickTrue(image->debug))
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-
   p=(const char *) NULL;
-  /* if properuty is in splay tree - return it and we are done */
   if (image->properties != (void *) NULL)
     {
       if (property == (const char *) NULL)
@@ -2023,13 +2127,8 @@ MagickExport const char *GetImageProperty(const Image *image,
     {
       if (LocaleNCompare("8bim:",property,5) == 0)
         {
-          if( IfMagickTrue(Get8BIMProperty(image,property,exception)) &&
-              (image->properties != (void *) NULL))
-            {
-              p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
-                image->properties,property);
-              return(p);
-            }
+          (void) Get8BIMProperty(image,property,exception);
+          break;
         }
       break;
     }
@@ -2038,28 +2137,24 @@ MagickExport const char *GetImageProperty(const Image *image,
     {
       if (LocaleNCompare("exif:",property,5) == 0)
         {
-          if( IfMagickTrue(GetEXIFProperty(image,property,exception)) &&
-              (image->properties != (void *) NULL))
-            {
-              p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
-                image->properties,property);
-              return(p);
-            }
+          (void) GetEXIFProperty(image,property,exception);
+          break;
         }
       break;
     }
     case 'I':
     case 'i':
     {
+      if ((LocaleNCompare("icc:",property,4) == 0) ||
+          (LocaleNCompare("icm:",property,4) == 0))
+        {
+          (void) GetICCProperty(image,property,exception);
+          break;
+        }
       if (LocaleNCompare("iptc:",property,5) == 0)
         {
-          if( IfMagickTrue(GetIPTCProperty(image,property,exception)) &&
-              (image->properties != (void *) NULL))
-            {
-              p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
-                image->properties,property);
-              return(p);
-            }
+          (void) GetIPTCProperty(image,property,exception);
+          break;
         }
       break;
     }
@@ -2068,20 +2163,21 @@ MagickExport const char *GetImageProperty(const Image *image,
     {
       if (LocaleNCompare("xmp:",property,4) == 0)
         {
-          if( IfMagickTrue(GetXMPProperty(image,property)) &&
-              (image->properties != (void *) NULL))
-            {
-              p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
-                image->properties,property);
-              return(p);
-            }
+          (void) GetXMPProperty(image,property);
+          break;
         }
       break;
     }
     default:
       break;
   }
-  return(p);
+  if (image->properties != (void *) NULL)
+    {
+      p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
+        image->properties,property);
+      return(p);
+    }
+  return((const char *) NULL);
 }
 \f
 /*
@@ -2097,29 +2193,29 @@ MagickExport const char *GetImageProperty(const Image *image,
 %
 %  GetMagickProperty() gets attributes or calculated values that is associated
 %  with a fixed known property name, or single letter property. It may be
-%  called if no image is defined (IMv7), in which case only global image info
-%  properities are available.
+%  called if no image is defined (IMv7), in which case only global image_info
+%  values are available.
 %
-%  This does not return, special profile or property expressions. Nor does it
-%  return free-form property strings, unless referenced by a single letter
-%  property name.
+%  This routine only handles specifically known properties.  It does not
+%  handle special prefixed properties, profiles, or expressions. Nor does
+%  it return any free-form property strings.
 %
-%  The returned string a reference to a string stored somewhere, it should not
-%  be freed.  If the string was generated (common) the string will be stored
-%  as teh image artifact 'get-property'.  This artifact or option may be
-%  deleted when no longer required, but is not guranteed to exist after this
-%  function is called.
+%  The returned string is stored in a structure somewhere, and should not be
+%  directly freed.  If the string was generated (common) the string will be
+%  stored as as either as artifact or option 'get-property'.  These may be
+%  deleted (cleaned up) when no longer required, but neither artifact or
+%  option is guranteed to exist.
 %
 %  The format of the GetMagickProperty method is:
 %
-%      const char *GetMagickProperty(const ImageInfo *image_info,Image *image,
+%      const char *GetMagickProperty(ImageInfo *image_info,Image *image,
 %        const char *property,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
-%    o image_info: the image info (required)
+%    o image_info: the image info (optional)
 %
-%    o image: the image (required, except for n,o,s,u,Z)
+%    o image: the image (optional)
 %
 %    o key: the key.
 %
@@ -2132,8 +2228,14 @@ MagickExport const char *GetImageProperty(const Image *image,
         "NoImageForProperty",format,arg); \
     return((const char *)NULL); \
   }
+#define WarnNoImageInfoReturn(format,arg) \
+  if (image_info == (ImageInfo *) NULL ) { \
+    (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, \
+        "NoImageInfoForProperty",format,arg); \
+    return((const char *)NULL); \
+  }
 
-static const char *GetMagickPropertyLetter(const ImageInfo *image_info,
+static const char *GetMagickPropertyLetter(ImageInfo *image_info,
   Image *image,const char letter,ExceptionInfo *exception)
 {
   char
@@ -2144,6 +2246,9 @@ static const char *GetMagickPropertyLetter(const ImageInfo *image_info,
 
   if (image != (Image *) NULL && IfMagickTrue(image->debug))
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  else if( image_info != (ImageInfo *) NULL && IfMagickTrue(image_info->debug))
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s","no-images");
+
   *value='\0';           /* formatted string */
   string=(char *) NULL;  /* constant string reference */
 
@@ -2244,6 +2349,7 @@ static const char *GetMagickPropertyLetter(const ImageInfo *image_info,
       break;
     }
     case 'o': /* Output Filename - for delegate use only */
+      WarnNoImageInfoReturn("\"%%%c\"",letter);
       string=image_info->filename;
       break;
     case 'p': /* Image index in current image list */
@@ -2301,6 +2407,7 @@ static const char *GetMagickPropertyLetter(const ImageInfo *image_info,
       break;
     }
     case 'u': /* Unique filename */
+      WarnNoImageInfoReturn("\"%%%c\"",letter);
       string=image_info->unique;
       break;
     case 'w': /* Image width (current) */
@@ -2313,45 +2420,43 @@ static const char *GetMagickPropertyLetter(const ImageInfo *image_info,
     case 'x': /* Image horizontal resolution (with units) */
     {
       WarnNoImageReturn("\"%%%c\"",letter);
-      (void) FormatLocaleString(value,MaxTextExtent,"%g %s",
-        image->resolution.x,CommandOptionToMnemonic(
-        MagickResolutionOptions,(ssize_t)image->units));
+      (void) FormatLocaleString(value,MaxTextExtent,"%.20g",
+        fabs(image->resolution.x) > MagickEpsilon ? image->resolution.x : 72.0);
       break;
     }
     case 'y': /* Image vertical resolution (with units) */
     {
       WarnNoImageReturn("\"%%%c\"",letter);
-      (void) FormatLocaleString(value,MaxTextExtent,"%g %s",
-        image->resolution.y,CommandOptionToMnemonic(MagickResolutionOptions,
-        (ssize_t) image->units));
+      (void) FormatLocaleString(value,MaxTextExtent,"%.20g",
+        fabs(image->resolution.y) > MagickEpsilon ? image->resolution.y : 72.0);
       break;
     }
     case 'z': /* Image depth as read in */
     {
       WarnNoImageReturn("\"%%%c\"",letter);
       (void) FormatLocaleString(value,MaxTextExtent,"%.20g",
-           (double) image->depth);
+        (double) image->depth);
       break;
     }
     case 'A': /* Image alpha channel  */
     {
       WarnNoImageReturn("\"%%%c\"",letter);
       string=CommandOptionToMnemonic(MagickBooleanOptions,
-           (ssize_t) image->alpha_trait);
+        (ssize_t) image->alpha_trait);
       break;
     }
     case 'C': /* Image compression method.  */
     {
       WarnNoImageReturn("\"%%%c\"",letter);
       string=CommandOptionToMnemonic(MagickCompressOptions,
-           (ssize_t) image->compression);
+        (ssize_t) image->compression);
       break;
     }
     case 'D': /* Image dispose method.  */
     {
       WarnNoImageReturn("\"%%%c\"",letter);
       string=CommandOptionToMnemonic(MagickDisposeOptions,
-           (ssize_t) image->dispose);
+        (ssize_t) image->dispose);
       break;
     }
     case 'G': /* Image size as geometry = "%wx%h" */
@@ -2365,7 +2470,7 @@ static const char *GetMagickPropertyLetter(const ImageInfo *image_info,
     {
       WarnNoImageReturn("\"%%%c\"",letter);
       (void) FormatLocaleString(value,MaxTextExtent,"%.20g",
-           (double) image->page.height);
+        (double) image->page.height);
       break;
     }
     case 'M': /* Magick filename - filename given incl. coder & read mods */
@@ -2392,22 +2497,24 @@ static const char *GetMagickPropertyLetter(const ImageInfo *image_info,
     {
       WarnNoImageReturn("\"%%%c\"",letter);
       (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-        image->quality);
+        (image->quality == 0 ? 92 : image->quality));
       break;
     }
     case 'S': /* Number of scenes in image list.  */
     {
+      WarnNoImageInfoReturn("\"%%%c\"",letter);
 #if 0 /* What is this number? -- it makes no sense - simplifing */
       if (image_info->number_scenes == 0)
          string="2147483647";
       else if ( image != (Image *) NULL )
         (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
                 image_info->scene+image_info->number_scenes);
-      else 
+      else
         string="0";
 #else
       (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-              image_info->number_scenes);
+        (image_info->number_scenes == 0 ? 2147483647 :
+         image_info->number_scenes));
 #endif
       break;
     }
@@ -2415,7 +2522,14 @@ static const char *GetMagickPropertyLetter(const ImageInfo *image_info,
     {
       WarnNoImageReturn("\"%%%c\"",letter);
       (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-               image->delay);
+        image->delay);
+      break;
+    }
+    case 'U': /* Image resolution units. */
+    {
+      WarnNoImageReturn("\"%%%c\"",letter);
+      string=CommandOptionToMnemonic(MagickResolutionOptions,
+        (ssize_t) image->units);
       break;
     }
     case 'W': /* layer canvas width */
@@ -2440,6 +2554,7 @@ static const char *GetMagickPropertyLetter(const ImageInfo *image_info,
       break;
     }
     case 'Z': /* Zero filename ??? */
+      WarnNoImageInfoReturn("\"%%%c\"",letter);
       string=image_info->zero;
       break;
     case '%': /* percent escaped */
@@ -2457,8 +2572,11 @@ static const char *GetMagickPropertyLetter(const ImageInfo *image_info,
         page.y);
       break;
     }
-    case '#': /* Image signature */
+    case '#':
     {
+      /*
+        Image signature.
+      */
       WarnNoImageReturn("\"%%%c\"",letter);
       (void) SignatureImage(image,exception);
       string=GetImageProperty(image,"signature",exception);
@@ -2468,14 +2586,25 @@ static const char *GetMagickPropertyLetter(const ImageInfo *image_info,
   if (string != (char *) NULL)
     return(string);
   if (*value != '\0')
-    { /* effectivally creates a cloned copy for return */
-      (void) SetImageArtifact(image,"get-property",value);
-      return(GetImageArtifact(image,"get-property"));
+    {
+      /*
+        Create a cloned copy of result.
+      */
+      if (image != (Image *)NULL)
+        {
+          (void) SetImageArtifact(image,"get-property",value);
+          return(GetImageArtifact(image,"get-property"));
+        }
+      else
+        {
+          (void) SetImageOption(image_info,"get-property",value);
+          return(GetImageOption(image_info,"get-property"));
+        }
     }
   return((char *)NULL);
 }
 
-MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
+MagickExport const char *GetMagickProperty(ImageInfo *image_info,
   Image *image,const char *property,ExceptionInfo *exception)
 {
   char
@@ -2485,13 +2614,15 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
     *string;
 
   assert(property[0] != '\0');
-  assert(image_info != (const ImageInfo *)NULL);
+  assert(image != (Image *)NULL || image_info != (ImageInfo *)NULL );
 
   if (property[1] == '\0')  /* single letter property request */
     return(GetMagickPropertyLetter(image_info,image,*property,exception));
 
-  if ((image != (Image *) NULL) && IfMagickTrue(image->debug))
+  if (image != (Image *) NULL && IfMagickTrue(image->debug))
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  else if( image_info != (ImageInfo *) NULL && IfMagickTrue(image_info->debug))
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s","no-images");
 
   *value='\0';           /* formated string */
   string=(char *) NULL;  /* constant string reference */
@@ -2507,6 +2638,12 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
           if (*value == '\0') string="";
           break;
         }
+      if (LocaleCompare("bit-depth",property) == 0)
+        {
+          (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
+            GetImageDepth(image, exception));
+          break;
+        }
       break;
     }
     case 'c':
@@ -2525,16 +2662,10 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
         }
       if (LocaleCompare("colorspace",property) == 0)
         {
-          ColorspaceType
-            colorspace;
-
           WarnNoImageReturn("\"%%[%s]\"",property);
           /* FUTURE: return actual colorspace - no 'gray' stuff */
-          colorspace=image->colorspace;
-          if( IfMagickTrue(IsImageGray(image,exception)) )
-            colorspace=GRAYColorspace;
           string=CommandOptionToMnemonic(MagickColorspaceOptions,(ssize_t)
-            colorspace);
+            image->colorspace);
           break;
         }
       if (LocaleCompare("copyright",property) == 0)
@@ -2582,10 +2713,9 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
             GetMagickPrecision(),image->gamma);
           break;
         }
-      if ( (image_info != (ImageInfo *) NULL) &&
-           (LocaleCompare("group",property) == 0) )
+      if (LocaleCompare("group",property) == 0)
         {
-          WarnNoImageReturn("\"%%[%s]\"",property);
+          WarnNoImageInfoReturn("\"%%[%s]\"",property);
           (void) FormatLocaleString(value,MaxTextExtent,"0x%lx",(unsigned long)
             image_info->group);
           break;
@@ -2691,28 +2821,70 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
             image->orientation);
           break;
         }
-      if ((image_info != (ImageInfo *) NULL) &&
-          (LocaleCompare("output",property) == 0))
+      if (LocaleCompare("output",property) == 0)
         {
+          WarnNoImageInfoReturn("\"%%[%s]\"",property);
           (void) CopyMagickString(value,image_info->filename,MaxTextExtent);
           break;
         }
      break;
     }
-/*  OBSOLETE  The 'page' of a image, is just the images index
-    This conficts with the -set page option that sets virtual canvas info
     case 'p':
     {
-      if (LocaleCompare("page",property) == 0)
+#if defined(MAGICKCORE_LCMS_DELEGATE)
+      if (LocaleCompare("profile:icc",property) == 0 ||
+          LocaleCompare("profile:icm",property) == 0)
         {
-          WarnNoImageReturn("\"%%[%s]\"",property);
-          (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-            GetImageIndexInList(image)+1);
+#if !defined(LCMS_VERSION) || (LCMS_VERSION < 2000)
+#define cmsUInt32Number  DWORD
+#endif
+
+          const StringInfo
+            *profile;
+
+          cmsHPROFILE
+            icc_profile;
+
+          profile=GetImageProfile(image,property+8);
+          if (profile == (StringInfo *) NULL)
+            break;
+
+          icc_profile=cmsOpenProfileFromMem(GetStringInfoDatum(profile),
+            (cmsUInt32Number) GetStringInfoLength(profile));
+          if (icc_profile != (cmsHPROFILE *) NULL)
+            {
+#if defined(LCMS_VERSION) && (LCMS_VERSION < 2000)
+              string=cmsTakeProductName(icc_profile);
+#else
+              (void) cmsGetProfileInfoASCII(icc_profile,cmsInfoDescription,
+                "en","US",value,MaxTextExtent);
+#endif
+              (void) cmsCloseProfile(icc_profile);
+            }
+      }
+#endif
+      if (LocaleCompare("profiles",property) == 0)
+        {
+          const char
+            *name;
+
+          ResetImageProfileIterator(image);
+          name=GetNextImageProfile(image);
+          if (name != (char *) NULL)
+            {
+              (void) CopyMagickString(value,name,MaxTextExtent);
+              name=GetNextImageProfile(image);
+              while (name != (char *) NULL)
+              {
+                ConcatenateMagickString(value,",",MaxTextExtent);
+                ConcatenateMagickString(value,name,MaxTextExtent);
+                name=GetNextImageProfile(image);
+              }
+            }
           break;
         }
       break;
     }
-*/
     case 'r':
     {
       if (LocaleCompare("resolution.x",property) == 0)
@@ -2735,8 +2907,8 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
     {
       if (LocaleCompare("scene",property) == 0)
         {
-          if ((image_info != (ImageInfo *) NULL) &&
-              (image_info->number_scenes != 0))
+          WarnNoImageInfoReturn("\"%%[%s]\"",property);
+          if (image_info->number_scenes != 0)
             (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
               image_info->scene);
           else {
@@ -2748,6 +2920,7 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
         }
       if (LocaleCompare("scenes",property) == 0)
         {
+          /* FUTURE: equivelent to %n? */
           WarnNoImageReturn("\"%%[%s]\"",property);
           (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
             GetImageListLength(image));
@@ -2775,7 +2948,8 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
             GetMagickPrecision(),skewness);
           break;
         }
-      if (LocaleCompare("standard-deviation",property) == 0)
+      if ((LocaleCompare("standard-deviation",property) == 0) ||
+          (LocaleCompare("standard_deviation",property) == 0))
         {
           double
             mean,
@@ -2802,12 +2976,20 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
     }
     case 'u':
     {
-      if ((image_info != (ImageInfo *) NULL) &&
-          (LocaleCompare("unique",property) == 0))
+      if (LocaleCompare("unique",property) == 0)
         {
+          WarnNoImageInfoReturn("\"%%[%s]\"",property);
           string=image_info->unique;
           break;
         }
+      if (LocaleCompare("units",property) == 0)
+        {
+          WarnNoImageReturn("\"%%[%s]\"",property);
+          string=CommandOptionToMnemonic(MagickResolutionOptions,(ssize_t)
+            image->units);
+          break;
+        }
+      if (LocaleCompare("copyright",property) == 0)
       break;
     }
     case 'v':
@@ -2856,9 +3038,9 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
     }
     case 'z':
     {
-      if ((image_info != (ImageInfo *) NULL) &&
-          (LocaleCompare("zero",property) == 0))
+      if (LocaleCompare("zero",property) == 0)
         {
+          WarnNoImageInfoReturn("\"%%[%s]\"",property);
           string=image_info->zero;
           break;
         }
@@ -2868,13 +3050,22 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
   if (string != (char *) NULL)
     return(string);
   if (*value != '\0')
-    { /* effectivally creates a cloned copy for return */
-      (void) SetImageArtifact(image,"get-property",value);
-      return(GetImageArtifact(image,"get-property"));
-    }
+  {
+    /* create a cloned copy of result, that will get cleaned up, eventually */
+    if (image != (Image *)NULL)
+      {
+        (void) SetImageArtifact(image,"get-property",value);
+        return(GetImageArtifact(image,"get-property"));
+      }
+    else
+      {
+        (void) SetImageOption(image_info,"get-property",value);
+        return(GetImageOption(image_info,"get-property"));
+      }
+  }
   return((char *)NULL);
 }
-#undef WarnNoImageRteurn
+#undef WarnNoImageReturn
 \f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -2949,7 +3140,7 @@ MagickExport char *GetNextImageProperty(const Image *image)
 %
 %  The format of the InterpretImageProperties method is:
 %
-%      char *InterpretImageProperties(const ImageInfo *image_info,
+%      char *InterpretImageProperties(ImageInfo *image_info,
 %        Image *image,const char *embed_text,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
@@ -2967,6 +3158,7 @@ MagickExport char *GetNextImageProperty(const Image *image)
 
 /* common inline code to expand the interpreted text string */
 #define ExtendInterpretText(string_length)  do { \
+DisableMSCWarning(4127) \
     size_t length=(string_length); \
     if ((size_t) (q-interpret_text+length+1) >= extent) \
      { extent+=length; \
@@ -2975,10 +3167,12 @@ MagickExport char *GetNextImageProperty(const Image *image)
        if (interpret_text == (char *) NULL) \
          return((char *)NULL); \
        q=interpret_text+strlen(interpret_text); \
-   } } while (0)  /* no trailing ; */
+   } } while (0)  /* no trailing ; */ \
+RestoreMSCWarning
 
 /* same but append the given string */
 #define AppendString2Text(string)  do { \
+DisableMSCWarning(4127) \
     size_t length=strlen((string)); \
     if ((size_t) (q-interpret_text+length+1) >= extent) \
      { extent+=length; \
@@ -2990,10 +3184,12 @@ MagickExport char *GetNextImageProperty(const Image *image)
       } \
      (void) CopyMagickString(q,(string),extent); \
      q+=length; \
-   } while (0)  /* no trailing ; */
+   } while (0)  /* no trailing ; */ \
+RestoreMSCWarning
 
 /* same but append a 'key' and 'string' pair */
 #define AppendKeyValue2Text(key,string)  do { \
+DisableMSCWarning(4127) \
     size_t length=strlen(key)+strlen(string)+2; \
     if ((size_t) (q-interpret_text+length+1) >= extent) \
      { extent+=length; \
@@ -3004,9 +3200,10 @@ MagickExport char *GetNextImageProperty(const Image *image)
       q=interpret_text+strlen(interpret_text); \
      } \
      q+=FormatLocaleString(q,extent,"%s=%s\n",(key),(string)); \
-   } while (0)  /* no trailing ; */
+   } while (0)  /* no trailing ; */ \
+RestoreMSCWarning
 
-MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
+MagickExport char *InterpretImageProperties(ImageInfo *image_info,
   Image *image,const char *embed_text,ExceptionInfo *exception)
 {
   char
@@ -3024,12 +3221,13 @@ MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
   MagickBooleanType
     number;
 
-  assert(image_info != (ImageInfo *)NULL);
-  if( image != (Image *) NULL && IfMagickTrue(image->debug) )
-    {
-      assert(image->signature == MagickSignature);
-      (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  }
+  assert(image == NULL || image->signature == MagickSignature);
+  assert(image_info == NULL || image_info->signature == MagickSignature);
+
+  if (image != (Image *) NULL && IfMagickTrue(image->debug))
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  else if( image_info != (ImageInfo *) NULL && IfMagickTrue(image_info->debug))
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s","no-image");
 
   if (embed_text == (const char *) NULL)
     return((char *) NULL);
@@ -3046,7 +3244,7 @@ MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
            OptionError,"UnableToAccessPath","%s",p);
        return((char *) NULL);
      }
-     return(FileToString(p,~0,exception));
+     return(FileToString(p,~0UL,exception));
   }
 
   /*
@@ -3086,9 +3284,8 @@ MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
           default:
             p++;
             *q++=(*p);
-            continue;
         }
-        continue; /* never reached! */
+        continue;
       case '&':
         if (LocaleNCompare("&lt;",p,4) == 0)
           *q++='<', p+=3;
@@ -3134,6 +3331,10 @@ MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
       if (string != (char *) NULL)
         {
           AppendString2Text(string);
+          if (image != (Image *) NULL)
+            (void)DeleteImageArtifact(image,"get-property");
+          if (image_info != (ImageInfo *) NULL)
+            (void)DeleteImageOption(image_info,"get-property");
           continue;
         }
       (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
@@ -3194,8 +3395,6 @@ MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
         (void) ThrowMagickException(exception,GetMagickModule(),
             OptionError,"UnbalancedBraces","\"%%[%s\"",pattern);
         interpret_text=DestroyString(interpret_text);
-        if (image != (Image *) NULL)
-          (void)DeleteImageArtifact(image,"get-property"); /* minor cleanup */
         return((char *)NULL);
       }
 
@@ -3243,7 +3442,7 @@ MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
           double
             value;
 
-          MagickBooleanType
+          MagickStatusType
             status;
 
           PixelInfo
@@ -3256,23 +3455,23 @@ MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
           }
           GetPixelInfo(image,&pixel);
           fx_info=AcquireFxInfo(image,pattern+6,exception);
-          status=FxEvaluateChannelExpression(fx_info,RedPixelChannel,
-               0,0,&value,exception);
+          status=FxEvaluateChannelExpression(fx_info,RedPixelChannel,0,0,
+            &value,exception);
           pixel.red=(double) QuantumRange*value;
-          status|=FxEvaluateChannelExpression(fx_info,GreenPixelChannel,
-               0,0,&value,exception);
+          status&=FxEvaluateChannelExpression(fx_info,GreenPixelChannel,0,0,
+            &value,exception);
           pixel.green=(double) QuantumRange*value;
-          status|=FxEvaluateChannelExpression(fx_info,BluePixelChannel,
-               0,0,&value,exception);
+          status&=FxEvaluateChannelExpression(fx_info,BluePixelChannel,0,0,
+            &value,exception);
           pixel.blue=(double) QuantumRange*value;
           if (image->colorspace == CMYKColorspace)
             {
-              status|=FxEvaluateChannelExpression(fx_info,BlackPixelChannel,
-                   0,0,&value,exception);
+              status&=FxEvaluateChannelExpression(fx_info,BlackPixelChannel,0,0,
+                &value,exception);
               pixel.black=(double) QuantumRange*value;
             }
-          status|=FxEvaluateChannelExpression(fx_info,AlphaPixelChannel,
-               0,0,&value,exception);
+          status&=FxEvaluateChannelExpression(fx_info,AlphaPixelChannel,0,0,
+            &value,exception);
           pixel.alpha=(double) QuantumRange*value;
           fx_info=DestroyFxInfo(fx_info);
           if( IfMagickTrue(status) )
@@ -3377,6 +3576,10 @@ MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
           if (string != (const char *) NULL)
             {
               AppendString2Text(string);
+              if (image != (Image *) NULL)
+                (void)DeleteImageArtifact(image,"get-property");
+              if (image_info != (ImageInfo *) NULL)
+                (void)DeleteImageOption(image_info,"get-property");
               continue;
             }
         }
@@ -3451,8 +3654,6 @@ PropertyLookupFailure:
 
   } /* for each char in 'embed_text' */
   *q='\0';
-  if (image != (Image *) NULL)
-    (void)DeleteImageArtifact(image,"get-property"); /* minor cleanup */
   return(interpret_text);
 }
 \f
@@ -3584,28 +3785,23 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
   assert(image->signature == MagickSignature);
   if( IfMagickTrue(image->debug) )
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-
-  /* Create splay-tree */
   if (image->properties == (void *) NULL)
     image->properties=NewSplayTree(CompareSplayTreeString,
-      RelinquishMagickMemory,RelinquishMagickMemory);
-
-  /* Delete property if NULL --  empty string values are valid! */
+      RelinquishMagickMemory,RelinquishMagickMemory);  /* create splay-tree */
   if (value == (const char *) NULL)
-    return(DeleteImageProperty(image,property));
+    return(DeleteImageProperty(image,property));  /* delete if NULL */
   status=MagickTrue;
-
-  /* Do not 'set' single letter properties - read only shorthand */
   if (strlen(property) <= 1)
     {
-      (void) ThrowMagickException(exception,GetMagickModule(),
-          OptionError,"SetReadOnlyProperty","`%s'",property);
+      /*
+        Do not 'set' single letter properties - read only shorthand.
+       */
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+        "SetReadOnlyProperty","`%s'",property);
       return(MagickFalse);
     }
 
   /* FUTURE: binary chars or quotes in key should produce a error */
-
-
   /* Set attributes with known names or special prefixes
      return result is found, or break to set a free form properity
   */
@@ -3641,8 +3837,8 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
     {
       if (LocaleCompare("channels",property) == 0)
         {
-          (void) ThrowMagickException(exception,GetMagickModule(),
-               OptionError,"SetReadOnlyProperty","`%s'",property);
+          (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+            "SetReadOnlyProperty","`%s'",property);
           return(MagickFalse);
         }
       if (LocaleCompare("colorspace",property) == 0)
@@ -3654,28 +3850,7 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
             value);
           if (colorspace < 0)
             return(MagickFalse); /* FUTURE: value exception?? */
-          image->colorspace=(ColorspaceType) colorspace;
-          image->rendering_intent=UndefinedIntent;
-          image->gamma=1.000f;
-          ResetMagickMemory(&image->chromaticity,0,sizeof(image->chromaticity));
-          if (IssRGBColorspace(image->colorspace) != MagickFalse)
-            {
-              image->rendering_intent=PerceptualIntent;
-              image->gamma=1.000f/2.200f;
-              image->chromaticity.red_primary.x=0.6400f;
-              image->chromaticity.red_primary.y=0.3300f;
-              image->chromaticity.red_primary.z=0.0300f;
-              image->chromaticity.green_primary.x=0.3000f;
-              image->chromaticity.green_primary.y=0.6000f;
-              image->chromaticity.green_primary.z=0.1000f;
-              image->chromaticity.blue_primary.x=0.1500f;
-              image->chromaticity.blue_primary.y=0.0600f;
-              image->chromaticity.blue_primary.z=0.7900f;
-              image->chromaticity.white_point.x=0.3127f;
-              image->chromaticity.white_point.y=0.3290f;
-              image->chromaticity.white_point.z=0.3583f;
-            }
-          return(MagickTrue);
+          return(SetImageColorspace(image,(ColorspaceType) colorspace,exception));
         }
       if (LocaleCompare("compose",property) == 0)
         {