]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/property.c
(no commit message)
[imagemagick] / MagickCore / property.c
index 9cdbd1386326be3a690f9576f0568ce1d127ab4f..507806d5d68cbcc2b0c2c30d95e258129f5320ca 100644 (file)
@@ -45,6 +45,8 @@
 #include "MagickCore/attribute.h"
 #include "MagickCore/cache.h"
 #include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colorspace-private.h"
 #include "MagickCore/compare.h"
 #include "MagickCore/constitute.h"
 #include "MagickCore/draw.h"
@@ -57,7 +59,6 @@
 #include "MagickCore/geometry.h"
 #include "MagickCore/histogram.h"
 #include "MagickCore/image.h"
-#include "MagickCore/image.h"
 #include "MagickCore/layer.h"
 #include "MagickCore/locale-private.h"
 #include "MagickCore/list.h"
@@ -94,7 +95,7 @@
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  CloneImageProperties() clones one or more image properties.
+%  CloneImageProperties() clones all the image properties to another image.
 %
 %  The format of the CloneImageProperties method is:
 %
@@ -186,7 +187,9 @@ MagickExport MagickBooleanType CloneImageProperties(Image *image,
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  DefineImageProperty() associates a key/value pair with an image property.
+%  DefineImageProperty() associates an assignment string of the form
+%  "key=value" with per-image artifact. It is equivelent to
+%  SetImageProperity().
 %
 %  The format of the DefineImageProperty method is:
 %
@@ -273,8 +276,8 @@ MagickExport MagickBooleanType DeleteImageProperty(Image *image,
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  DestroyImageProperties() releases memory associated with image property
-%  values.
+%  DestroyImageProperties() destroys all properities and associated memory
+%  attached to the given image.
 %
 %  The format of the DestroyDefines method is:
 %
@@ -367,6 +370,9 @@ MagickExport MagickBooleanType FormatImageProperty(Image *image,
 %
 %  GetImageProperty() gets a value associated with an image property.
 %
+%  The returned string is a constant string in the tree and should NOT be
+%  freed by the caller.
+%
 %  The format of the GetImageProperty method is:
 %
 %      const char *GetImageProperty(const Image *image,const char *key,
@@ -615,7 +621,7 @@ static MagickBooleanType Get8BIMProperty(const Image *image,const char *key,
     if ((count != 0) && ((size_t) count <= length))
       {
         resource=(char *) NULL;
-        if (~(1UL*count) >= (MaxTextExtent-1))
+        if (~((size_t) count) >= (MaxTextExtent-1))
           resource=(char *) AcquireQuantumMemory((size_t) count+MaxTextExtent,
             sizeof(*resource));
         if (resource != (char *) NULL)
@@ -652,7 +658,7 @@ static MagickBooleanType Get8BIMProperty(const Image *image,const char *key,
       We have the resource of interest.
     */
     attribute=(char *) NULL;
-    if (~(1UL*count) >= (MaxTextExtent-1))
+    if (~((size_t) count) >= (MaxTextExtent-1))
       attribute=(char *) AcquireQuantumMemory((size_t) count+MaxTextExtent,
         sizeof(*attribute));
     if (attribute != (char *) NULL)
@@ -1089,7 +1095,7 @@ static MagickBooleanType GetEXIFProperty(const Image *image,
       { 0x1001c, "exif:GPSAreaInformation" },
       { 0x1001d, "exif:GPSDateStamp" },
       { 0x1001e, "exif:GPSDifferential" },
-      {  0x0000, NULL}
+      { 0x00000, (const char *) NULL }
     };
 
   const StringInfo
@@ -1397,7 +1403,7 @@ static MagickBooleanType GetEXIFProperty(const Image *image,
             case EXIF_FMT_STRING:
             {
               value=(char *) NULL;
-              if (~(1UL*number_bytes) >= 1)
+              if (~((size_t) number_bytes) >= 1)
                 value=(char *) AcquireQuantumMemory((size_t) number_bytes+1UL,
                   sizeof(*value));
               if (value != (char *) NULL)
@@ -1419,12 +1425,14 @@ static MagickBooleanType GetEXIFProperty(const Image *image,
           if (value != (char *) NULL)
             {
               char
-                key[MaxTextExtent];
+                *key;
 
               register const char
                 *p;
 
-              (void) CopyMagickString(key,property,MaxTextExtent);
+              key=AcquireString(property);
+              if (level == 2)
+                (void) SubstituteString(&key,"exif:","exif:thumbnail:");
               switch (all)
               {
                 case 1:
@@ -1470,6 +1478,7 @@ static MagickBooleanType GetEXIFProperty(const Image *image,
               if (p == (const char *) NULL)
                 (void) SetImageProperty((Image *) image,key,value,exception);
               value=DestroyString(value);
+              key=DestroyString(key);
               status=MagickTrue;
             }
         }
@@ -1980,7 +1989,7 @@ MagickExport const char *GetImageProperty(const Image *image,
   FxInfo
     *fx_info;
 
-  MagickRealType
+  double
     alpha;
 
   MagickStatusType
@@ -2003,7 +2012,7 @@ MagickExport const char *GetImageProperty(const Image *image,
             image->properties);
           return(p);
         }
-      if (LocaleNCompare("fx:",property,3) != 0)
+      if (LocaleNCompare("fx:",property,3) != 0) /* NOT %[fx:..] !!!! */
         {
           p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
             image->properties,property);
@@ -2099,22 +2108,22 @@ MagickExport const char *GetImageProperty(const Image *image,
           fx_info=AcquireFxInfo(image,property+6,exception);
           status=FxEvaluateChannelExpression(fx_info,RedPixelChannel,0,0,
             &alpha,exception);
-          pixel.red=(MagickRealType) QuantumRange*alpha;
+          pixel.red=(double) QuantumRange*alpha;
           status|=FxEvaluateChannelExpression(fx_info,GreenPixelChannel,0,0,
             &alpha,exception);
-          pixel.green=(MagickRealType) QuantumRange*alpha;
+          pixel.green=(double) QuantumRange*alpha;
           status|=FxEvaluateChannelExpression(fx_info,BluePixelChannel,0,0,
             &alpha,exception);
-          pixel.blue=(MagickRealType) QuantumRange*alpha;
+          pixel.blue=(double) QuantumRange*alpha;
           if (image->colorspace == CMYKColorspace)
             {
               status|=FxEvaluateChannelExpression(fx_info,BlackPixelChannel,0,0,
                 &alpha,exception);
-              pixel.black=(MagickRealType) QuantumRange*alpha;
+              pixel.black=(double) QuantumRange*alpha;
             }
           status|=FxEvaluateChannelExpression(fx_info,AlphaPixelChannel,0,0,
             &alpha,exception);
-          pixel.alpha=(MagickRealType) QuantumRange*(1.0-alpha);
+          pixel.alpha=(double) QuantumRange*(1.0-alpha);
           fx_info=DestroyFxInfo(fx_info);
           if( IfMagickTrue(status) )
             {
@@ -2162,18 +2171,21 @@ 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 properity.
+%  with a fixed known property name, or single letter property.
 %
-%  This does not return, special profile or properity expressions. Nor does it
-%  return free-form properity strings, unless referenced by a single letter
-%  properity name.
+%  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.
 %
-%  The returned string should be freed using DestoryString() when finished.
+%  The returned string is stored as the image artifact 'get-property' (not as
+%  another property), and as such should not be freed. Later calls however
+%  will overwrite this value so if needed for a longer period a copy should be
+%  made.  This artifact can be deleted when no longer required.
 %
 %  The format of the GetMagickProperty method is:
 %
 %      const char *GetMagickProperty(const ImageInfo *image_info,Image *image,
-%        const char *properity,ExceptionInfo *exception)
+%        const char *property,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -2190,19 +2202,17 @@ static const char *GetMagickPropertyLetter(const ImageInfo *image_info,
   Image *image,const char letter,ExceptionInfo *exception)
 {
   char
-    value[MaxTextExtent],
-    *clone;
-
-  if (image != (Image *) NULL && image->debug != MagickFalse)
-    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
-      image->filename);
+    value[MaxTextExtent];
 
-  *value='\0';
-  clone=(char *)NULL;
+  const char
+    *string;
 
+  if (image != (Image *) NULL && IfMagickTrue(image->debug))
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  *value='\0';  /* formatted string */
+  string=(char *) NULL;  /* constant string reference */
   switch (letter)
   {
-
     case 'b':  /* image size read in - in bytes */
     {
       (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
@@ -2212,9 +2222,11 @@ static const char *GetMagickPropertyLetter(const ImageInfo *image_info,
       ConcatenateMagickString(value,"B",MaxTextExtent);
       break;
     }
-    case 'c':  /* image comment property */
+    case 'c':  /* image comment property - empty string by default */
     {
-      clone=ConstantString(GetImageProperty(image,"comment",exception));
+      string=GetImageProperty(image,"comment",exception);
+      if (string == (const char *) NULL)
+        string="";
       break;
     }
     case 'd':  /* Directory component of filename */
@@ -2235,53 +2247,57 @@ static const char *GetMagickPropertyLetter(const ImageInfo *image_info,
     case 'g': /* Image geometry, canvas and offset  %Wx%H+%X+%Y */
     {
       (void) FormatLocaleString(value,MaxTextExtent,"%.20gx%.20g%+.20g%+.20g",
-           (double) image->page.width,(double) image->page.height,
-           (double) image->page.x,(double) image->page.y);
+        (double) image->page.width,(double) image->page.height,
+        (double) image->page.x,(double) image->page.y);
       break;
     }
     case 'h': /* Image height (current) */
     {
-      (void) FormatLocaleString(value,MaxTextExtent,"%.20g",
-           (double) (image->rows != 0 ? image->rows : image->magick_rows));
+      (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
+        (image->rows != 0 ? image->rows : image->magick_rows));
       break;
     }
     case 'i': /* Filename last used for image (read or write) */
     {
-      clone=ConstantString(image->filename);
+      string=image->filename;
       break;
     }
     case 'k': /* Number of unique colors  */
     {
-      /* FUTURE: ensure this does not generate the formated comment! */
+      /*
+        FUTURE: ensure this does not generate the formatted comment!
+      */
       (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-            GetNumberColors(image,(FILE *) NULL,exception));
+        GetNumberColors(image,(FILE *) NULL,exception));
       break;
     }
-    case 'l': /* Image label  */
+    case 'l': /* Image label property - empty string by default */
     {
-      clone=ConstantString(GetImageProperty(image,"label",exception));
+      string=GetImageProperty(image,"label",exception);
+      if ( string == (const char *)NULL)
+        string="";
       break;
     }
     case 'm': /* Image format (file magick) */
     {
-      clone=ConstantString(image->magick);
+      string=image->magick;
       break;
     }
     case 'n': /* Number of images in the list.  */
     {
       (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-              GetImageListLength(image));
+        GetImageListLength(image));
       break;
     }
     case 'o': /* Output Filename - for delegate use only */
     {
-      clone=ConstantString(image_info->filename);
+      string=image_info->filename;
       break;
     }
     case 'p': /* Image index in current image list -- As 'n' OBSOLETE */
     {
       (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-             GetImageIndexInList(image));
+        GetImageIndexInList(image));
       break;
     }
     case 'q': /* Quantum depth of image in memory */
@@ -2299,19 +2315,19 @@ static const char *GetMagickPropertyLetter(const ImageInfo *image_info,
       if (IfMagickTrue(IsImageGray(image,exception)))
         colorspace=GRAYColorspace;
       (void) FormatLocaleString(value,MaxTextExtent,"%s %s %s",
-        CommandOptionToMnemonic(MagickClassOptions,(ssize_t)image->storage_class),
+        CommandOptionToMnemonic(MagickClassOptions,(ssize_t) image->storage_class),
         CommandOptionToMnemonic(MagickColorspaceOptions,(ssize_t) colorspace),
-        IfMagickTrue(image->matte)?"Matte":"");
+        image->alpha_trait == BlendPixelTrait ? "Matte" : "");
       break;
     }
     case 's': /* Image scene number */
     {
       if (image_info->number_scenes != 0)
         (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-             image_info->scene);
+          image_info->scene);
       else
         (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-             image->scene);
+          image->scene);
       break;
     }
     case 't': /* Base filename without directory or extention */
@@ -2321,40 +2337,39 @@ static const char *GetMagickPropertyLetter(const ImageInfo *image_info,
     }
     case 'u': /* Unique filename */
     {
-      clone=ConstantString(image_info->unique);
+      string=image_info->unique;
       break;
     }
     case 'w': /* Image width (current) */
     {
       (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-         (image->columns != 0 ? image->columns : image->magick_columns));
+        (image->columns != 0 ? image->columns : image->magick_columns));
       break;
     }
     case 'x': /* Image horizontal resolution (with units) */
     {
       (void) FormatLocaleString(value,MaxTextExtent,"%g %s",
-           image->resolution.x,CommandOptionToMnemonic(
-           MagickResolutionOptions,(ssize_t)image->units));
+        image->resolution.x,CommandOptionToMnemonic(
+        MagickResolutionOptions,(ssize_t)image->units));
       break;
     }
     case 'y': /* Image vertical resolution (with units) */
     {
       (void) FormatLocaleString(value,MaxTextExtent,"%g %s",
-           image->resolution.y,CommandOptionToMnemonic(
-           MagickResolutionOptions,(ssize_t)image->units));
+        image->resolution.y,CommandOptionToMnemonic(MagickResolutionOptions,
+        (ssize_t) image->units));
       break;
     }
     case 'z': /* Image depth as read in */
     {
       (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-           image->depth);
+        image->depth);
       break;
     }
     case 'A': /* Image alpha channel  */
     {
       (void) FormatLocaleString(value,MaxTextExtent,"%s",
-         CommandOptionToMnemonic(MagickBooleanOptions,(ssize_t)
-           image->matte));
+        CommandOptionToMnemonic(MagickBooleanOptions,(ssize_t) image->alpha_trait));
       break;
     }
     case 'C': /* Image compression method.  */
@@ -2367,81 +2382,80 @@ static const char *GetMagickPropertyLetter(const ImageInfo *image_info,
     case 'D': /* Image dispose method.  */
     {
       (void) FormatLocaleString(value,MaxTextExtent,"%s",
-        CommandOptionToMnemonic(MagickDisposeOptions,(ssize_t)
-          image->dispose));
+        CommandOptionToMnemonic(MagickDisposeOptions,(ssize_t) image->dispose));
       break;
     }
     case 'G': /* Image size as geometry = "%wx%h" */
     {
       (void) FormatLocaleString(value,MaxTextExtent,"%.20gx%.20g",
-           (double)image->magick_columns,(double) image->magick_rows);
+        (double)image->magick_columns,(double) image->magick_rows);
       break;
     }
     case 'H': /* layer canvas height */
     {
       (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-           image->page.height);
+        image->page.height);
       break;
     }
     case 'M': /* Magick filename - filename given incl. coder & read mods */
     {
-      clone=ConstantString(image->magick_filename);
+      string=image->magick_filename;
       break;
     }
     case 'O': /* layer canvas offset with sign = "+%X+%Y" */
     {
-      (void) FormatLocaleString(value,MaxTextExtent,"%+ld%+ld",
-          (long) image->page.x,(long) image->page.y);
+      (void) FormatLocaleString(value,MaxTextExtent,"%+ld%+ld",(long)
+        image->page.x,(long) image->page.y);
       break;
     }
     case 'P': /* layer canvas page size = "%Wx%H" */
     {
       (void) FormatLocaleString(value,MaxTextExtent,"%.20gx%.20g",
-           (double) image->page.width,(double) image->page.height);
+        (double) image->page.width,(double) image->page.height);
       break;
     }
     case 'Q': /* image compression quality */
     {
       (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-          image->quality);
+        image->quality);
       break;
     }
     case 'S': /* Image scenes  ???? */
     {
       if (image_info->number_scenes == 0)
-        clone=ConstantString("2147483647");
+        string="2147483647";
       else
         (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-            image_info->scene+image_info->number_scenes);
+          image_info->scene+image_info->number_scenes);
       break;
     }
     case 'T': /* image time delay for animations */
     {
       (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-          image->delay);
+        image->delay);
       break;
     }
     case 'W': /* layer canvas width */
     {
       (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-           image->page.width);
+        image->page.width);
       break;
     }
     case 'X': /* layer canvas X offset */
     {
-      (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-           image->page.x);
+      (void) FormatLocaleString(value,MaxTextExtent,"%+.20g",(double)
+        image->page.x);
       break;
     }
     case 'Y': /* layer canvas Y offset */
     {
-      (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-           image->page.y);
+      (void) FormatLocaleString(value,MaxTextExtent,"%+.20g",(double)
+        image->page.y);
       break;
     }
     case 'Z': /* Zero filename ??? */
     {
-      clone=ConstantString(image_info->zero);
+      string=image_info->zero;
       break;
     }
     case '@': /* Trim bounding box, without Trimming! */
@@ -2451,26 +2465,30 @@ static const char *GetMagickPropertyLetter(const ImageInfo *image_info,
 
       page=GetImageBoundingBox(image,exception);
       (void) FormatLocaleString(value,MaxTextExtent,"%.20gx%.20g%+.20g%+.20g",
-           (double) page.width,(double) page.height,
-           (double) page.x,(double) page.y);
+        (double) page.width,(double) page.height,(double) page.x,(double)
+        page.y);
       break;
     }
     case '#': /* Image signature */
     {
       (void) SignatureImage(image,exception);
-      clone=ConstantString(GetImageProperty(image,"signature",exception));
+      string=GetImageProperty(image,"signature",exception);
       break;
     }
     case '%': /* percent escaped */
     {
-      clone=ConstantString("%");
+      string="%";
       break;
     }
   }
-  /* FUTURE: save it as a 'special' property - for return */
   if (*value != '\0')
-    clone=ConstantString(value);
-  return(clone);
+    string=value;
+  if (string != (char *) NULL)
+    {
+      (void) SetImageArtifact(image,"get-property",string);
+      return(GetImageArtifact(image,"get-property"));
+    }
+  return((char *)NULL);
 }
 
 MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
@@ -2479,17 +2497,22 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
   char
     value[MaxTextExtent];
 
-  assert(property[0] != '\0');
-  if ( property[1] == '\0')  /* single letter properity request */
-    return( GetMagickPropertyLetter(image_info,image,*property,exception) );
+  const char
+    *string;
 
-  *value='\0';
+  assert(property[0] != '\0');
+  if (property[1] == '\0')  /* single letter property request */
+    return(GetMagickPropertyLetter(image_info,image,*property,exception));
+  if ((image != (Image *) NULL) && IfMagickTrue(image->debug))
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  *value='\0';  /* formated string */
+  string=(char *) NULL;  /* constant string reference */
   switch (*property)
   {
     case 'b':
     {
-      if ((LocaleNCompare("base",property,4) == 0) ||
-          (LocaleNCompare("basename",property,8) == 0) )
+      if ((LocaleCompare("base",property) == 0) ||
+          (LocaleCompare("basename",property) == 0) )
         {
           GetPathComponent(image->magick_filename,BasePath,value);
           break;
@@ -2498,36 +2521,31 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
     }
     case 'c':
     {
-      if (LocaleNCompare("channels",property,8) == 0)
+      if (LocaleCompare("channels",property) == 0)
         {
-          /*
-            Image channels.
-          */
+          /* FUTURE: return actual image channels */
           (void) FormatLocaleString(value,MaxTextExtent,"%s",
             CommandOptionToMnemonic(MagickColorspaceOptions,(ssize_t)
             image->colorspace));
           LocaleLower(value);
-          if( IfMagickTrue(image->matte) )
+          if( image->alpha_trait == BlendPixelTrait )
             (void) ConcatenateMagickString(value,"a",MaxTextExtent);
           break;
         }
-      if (LocaleNCompare("colorspace",property,10) == 0)
+      if (LocaleCompare("colorspace",property) == 0)
         {
           ColorspaceType
             colorspace;
 
-          /*
-            Image storage class and colorspace.
-          */
+          /* FUTURE: return actual colorspace - no 'gray' stuff */
           colorspace=image->colorspace;
           if( IfMagickTrue(IsImageGray(image,exception)) )
             colorspace=GRAYColorspace;
-          (void) FormatLocaleString(value,MaxTextExtent,"%s",
-            CommandOptionToMnemonic(MagickColorspaceOptions,(ssize_t)
-            colorspace));
+          string=CommandOptionToMnemonic(MagickColorspaceOptions,(ssize_t)
+            colorspace);
           break;
         }
-      if (LocaleNCompare("copyright",property,9) == 0)
+      if (LocaleCompare("copyright",property) == 0)
         {
           (void) CopyMagickString(value,GetMagickCopyright(),MaxTextExtent);
           break;
@@ -2536,13 +2554,13 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
     }
     case 'd':
     {
-      if (LocaleNCompare("depth",property,5) == 0)
+      if (LocaleCompare("depth",property) == 0)
         {
           (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
             image->depth);
           break;
         }
-      if (LocaleNCompare("directory",property,9) == 0)
+      if (LocaleCompare("directory",property) == 0)
         {
           GetPathComponent(image->magick_filename,HeadPath,value);
           break;
@@ -2551,7 +2569,7 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
     }
     case 'e':
     {
-      if (LocaleNCompare("extension",property,9) == 0)
+      if (LocaleCompare("extension",property) == 0)
         {
           GetPathComponent(image->magick_filename,ExtensionPath,value);
           break;
@@ -2560,18 +2578,24 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
     }
     case 'g':
     {
+      if (LocaleCompare("gamma",property) == 0)
+        {
+          (void) FormatLocaleString(value,MaxTextExtent,"%.*g",
+            GetMagickPrecision(),image->gamma);
+          break;
+        }
       if ( (image_info != (ImageInfo *) NULL) &&
-           (LocaleNCompare("group",property,5) == 0) )
+           (LocaleCompare("group",property) == 0) )
         {
-          (void) FormatLocaleString(value,MaxTextExtent,"0x%lx",
-            (unsigned long) image_info->group);
+          (void) FormatLocaleString(value,MaxTextExtent,"0x%lx",(unsigned long)
+            image_info->group);
           break;
         }
       break;
     }
     case 'h':
     {
-      if (LocaleNCompare("height",property,6) == 0)
+      if (LocaleCompare("height",property) == 0)
         {
           (void) FormatLocaleString(value,MaxTextExtent,"%.20g",
             image->magick_rows != 0 ? (double) image->magick_rows : 256.0);
@@ -2581,16 +2605,16 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
     }
     case 'i':
     {
-      if (LocaleNCompare("input",property,5) == 0)
+      if (LocaleCompare("input",property) == 0)
         {
-          (void) CopyMagickString(value,image->filename,MaxTextExtent);
+          string=image->filename;
           break;
         }
       break;
     }
     case 'k':
     {
-      if (LocaleNCompare("kurtosis",property,8) == 0)
+      if (LocaleCompare("kurtosis",property) == 0)
         {
           double
             kurtosis,
@@ -2605,12 +2629,12 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
     }
     case 'm':
     {
-      if (LocaleNCompare("magick",property,6) == 0)
+      if (LocaleCompare("magick",property) == 0)
         {
-          (void) CopyMagickString(value,image->magick,MaxTextExtent);
+          string=image->magick;
           break;
         }
-      if (LocaleNCompare("max",property,3) == 0)
+      if (LocaleCompare("max",property) == 0)
         {
           double
             maximum,
@@ -2621,19 +2645,18 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
             GetMagickPrecision(),maximum);
           break;
         }
-      if (LocaleNCompare("mean",property,4) == 0)
+      if (LocaleCompare("mean",property) == 0)
         {
           double
             mean,
             standard_deviation;
 
-          (void) GetImageMean(image,&mean,&standard_deviation,
-             exception);
+          (void) GetImageMean(image,&mean,&standard_deviation,exception);
           (void) FormatLocaleString(value,MaxTextExtent,"%.*g",
             GetMagickPrecision(),mean);
           break;
         }
-      if (LocaleNCompare("min",property,3) == 0)
+      if (LocaleCompare("min",property) == 0)
         {
           double
             maximum,
@@ -2648,25 +2671,24 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
     }
     case 'o':
     {
-      if (LocaleNCompare("opaque",property,6) == 0)
+      if (LocaleCompare("opaque",property) == 0)
         {
           MagickBooleanType
             opaque;
 
           opaque=IsImageOpaque(image,exception);
-          (void) CopyMagickString(value,IfMagickTrue(opaque)?"true":"false",
-               MaxTextExtent);
+          (void) CopyMagickString(value,IfMagickTrue(opaque) ? "true" : "false",
+            MaxTextExtent);
           break;
         }
-      if (LocaleNCompare("orientation",property,11) == 0)
+      if (LocaleCompare("orientation",property) == 0)
         {
-          (void) FormatLocaleString(value,MaxTextExtent,"%s",
-            CommandOptionToMnemonic(MagickOrientationOptions,(ssize_t)
-            image->orientation));
+          string=CommandOptionToMnemonic(MagickOrientationOptions,(ssize_t)
+            image->orientation);
           break;
         }
-      if ( (image_info != (ImageInfo *) NULL) &&
-           (LocaleNCompare("output",property,6) == 0) )
+      if ((image_info != (ImageInfo *) NULL) &&
+          (LocaleCompare("output",property) == 0))
         {
           (void) CopyMagickString(value,image_info->filename,MaxTextExtent);
           break;
@@ -2675,7 +2697,7 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
     }
     case 'p':
     {
-      if (LocaleNCompare("page",property,4) == 0)
+      if (LocaleCompare("page",property) == 0)
         {
           (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
             GetImageIndexInList(image)+1);
@@ -2685,15 +2707,15 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
     }
     case 'r':
     {
-      /* FUTURE: Obsolete */
-      if (LocaleNCompare("resolution.x",property,11) == 0)
+      /* This matches %[fx:resolution.x] */
+      if (LocaleCompare("resolution.x",property) == 0)
         {
           (void) FormatLocaleString(value,MaxTextExtent,"%g",
             image->resolution.x);
           break;
         }
-      /* FUTURE: Obsolete */
-      if (LocaleNCompare("resolution.y",property,11) == 0)
+      /* This matches %[fx:resolution.y] */
+      if (LocaleCompare("resolution.y",property) == 0)
         {
           (void) FormatLocaleString(value,MaxTextExtent,"%g",
             image->resolution.y);
@@ -2703,24 +2725,24 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
     }
     case 's':
     {
-      if (LocaleNCompare("scene",property,5) == 0)
+      if (LocaleCompare("scene",property) == 0)
         {
-          if ( (image_info != (ImageInfo *) NULL) &&
-               (image_info->number_scenes != 0) )
+          if ((image_info != (ImageInfo *) NULL) &&
+              (image_info->number_scenes != 0))
             (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-                image_info->scene);
+              image_info->scene);
           else
             (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
-                image->scene);
+              image->scene);
           break;
         }
-      if (LocaleNCompare("scenes",property,6) == 0)
+      if (LocaleCompare("scenes",property) == 0)
         {
           (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
             GetImageListLength(image));
           break;
         }
-      if (LocaleNCompare("size",property,4) == 0)
+      if (LocaleCompare("size",property) == 0)
         {
           char
             format[MaxTextExtent];
@@ -2729,7 +2751,7 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
           (void) FormatLocaleString(value,MaxTextExtent,"%sB",format);
           break;
         }
-      if (LocaleNCompare("skewness",property,8) == 0)
+      if (LocaleCompare("skewness",property) == 0)
         {
           double
             kurtosis,
@@ -2740,43 +2762,51 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
             GetMagickPrecision(),skewness);
           break;
         }
-      if (LocaleNCompare("standard-deviation",property,18) == 0)
+      if (LocaleCompare("standard-deviation",property) == 0)
         {
           double
             mean,
             standard_deviation;
 
-          (void) GetImageMean(image,&mean,&standard_deviation,
-            exception);
+          (void) GetImageMean(image,&mean,&standard_deviation,exception);
           (void) FormatLocaleString(value,MaxTextExtent,"%.*g",
             GetMagickPrecision(),standard_deviation);
           break;
         }
        break;
     }
+    case 't':
+    {
+      if (LocaleCompare("type",property) == 0)
+        {
+          string=CommandOptionToMnemonic(MagickTypeOptions,(ssize_t)
+            GetImageType(image,exception));
+          break;
+        }
+       break;
+    }
     case 'u':
     {
-      if ( (image_info != (ImageInfo *) NULL) &&
-           (LocaleNCompare("unique",property,6) == 0) )
+      if ((image_info != (ImageInfo *) NULL) &&
+          (LocaleCompare("unique",property) == 0))
         {
-          (void) CopyMagickString(value,image_info->unique,MaxTextExtent);
+          string=image_info->unique;
           break;
         }
       break;
     }
     case 'v':
     {
-      if (LocaleNCompare("version",property,7) == 0)
+      if (LocaleCompare("version",property) == 0)
         {
-          (void) CopyMagickString(value,GetMagickVersion((size_t *) NULL),
-            MaxTextExtent);
+          string=GetMagickVersion((size_t *) NULL);
           break;
         }
       break;
     }
     case 'w':
     {
-      if (LocaleNCompare("width",property,5) == 0)
+      if (LocaleCompare("width",property) == 0)
         {
           (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
             (image->magick_columns != 0 ? image->magick_columns : 256));
@@ -2784,43 +2814,47 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
         }
       break;
     }
-    case 'x': /* ( X resolution, (with units) */
+    case 'x': /* FUTURE: Obsolete X resolution */
     {
-      if ((LocaleNCompare("xresolution",property,11) == 0) ||
-          (LocaleNCompare("x-resolution",property,12) == 0) )
+      if ((LocaleCompare("xresolution",property) == 0) ||
+          (LocaleCompare("x-resolution",property) == 0) )
         {
           (void) FormatLocaleString(value,MaxTextExtent,"%.20g",
-               image->resolution.x);
+            image->resolution.x);
           break;
         }
       break;
     }
-    case 'y': /* ( Y resolution, (with units) */
+    case 'y': /* FUTURE: Obsolete Y resolution */
     {
-      if ((LocaleNCompare("yresolution",property,11) == 0) ||
-          (LocaleNCompare("y-resolution",property,12) == 0) )
+      if ((LocaleCompare("yresolution",property) == 0) ||
+          (LocaleCompare("y-resolution",property) == 0) )
         {
           (void) FormatLocaleString(value,MaxTextExtent,"%.20g",
-               image->resolution.y);
+            image->resolution.y);
           break;
         }
       break;
     }
     case 'z':
     {
-      if ( (image_info != (ImageInfo *) NULL) &&
-           (LocaleNCompare("zero",property,4) == 0) )
+      if ((image_info != (ImageInfo *) NULL) &&
+          (LocaleCompare("zero",property) == 0))
         {
-          (void) CopyMagickString(value,image_info->zero,MaxTextExtent);
+          string=image_info->zero;
           break;
         }
       break;
     }
   }
-  /* FUTURE: save it as a 'special' property entry - for return */
-  if (*value == '\0')
-    return(NULL);
-  return(ConstantString(value));
+  if (*value != '\0')
+    string=value;
+  if (string != (char *)NULL)
+    {
+      (void) SetImageArtifact(image,"get-property", string);
+      return(GetImageArtifact(image,"get-property"));
+    }
+  return((char *)NULL);
 }
 \f
 /*
@@ -2834,7 +2868,7 @@ MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  GetNextImageProperty() gets the next free-form string properity name.
+%  GetNextImageProperty() gets the next free-form string property name.
 %
 %  The format of the GetNextImageProperty method is:
 %
@@ -2876,22 +2910,23 @@ MagickExport char *GetNextImageProperty(const Image *image)
 %     &lt; &gt; &amp;   replaced by '<', '>', '&' resp.
 %     %%                replaced by percent
 %
-%     %x            where 'x' is a single letter, case sensitive).
-%     %[type:name]  where 'type' is specifically known prefix.
+%     %x %[x]       where 'x' is a single letter properity, case sensitive).
+%     %[type:name]  where 'type' a is special and known prefix.
 %     %[name]       where 'name' is a specifically known attribute, calculated
-%                   value, or a per-image properity string name, or a per-image
-%                   'artifact' (as generated from a global option)
+%                   value, or a per-image property string name, or a per-image
+%                   'artifact' (as generated from a global option).
+%                   It may contain ':' as long as the prefix is not special.
 %
-%  Single letter % substitutions will only happen if the preceeding character
-%  is NOT a number. But braced substitutions will always be performed. This
-%  prevents typical usage of percent in 'geometry arguments' from being
-%  substituted unexpectedly.
+%  Single letter % substitutions will only happen if the character before the
+%  percent is NOT a number. But braced substitutions will always be performed.
+%  This prevents the typical usage of percent in a interpreted geometry
+%  argument from being substituted when the percent is a geometry flag.
 %
 %  If 'glob-expresions' ('*' or '?' characters) is used for 'name' it may be
 %  used as a search pattern to print multiple lines of "name=value\n" pairs of
 %  the associacted set of properities.
 %
-%  The returned string must be freed using DestoryString().
+%  The returned string must be freed using DestoryString() by the caller.
 %
 %  The format of the InterpretImageProperties method is:
 %
@@ -2934,16 +2969,19 @@ MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
   if( IfMagickTrue(image->debug) )
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
 
-  if ((embed_text == (const char *) NULL) || (*embed_text == '\0'))
+  if ((embed_text == (const char *) NULL))
     return((char *) NULL);
   p=embed_text;
 
+  if (*p == '\0')
+    return(ConstantString(""));
+
   /* handle a '@' replace string from file */
   if (*p == '@') {
      p++;
      if (*p != '-' && IfMagickFalse(IsPathAccessible(p)) ) {
        (void) ThrowMagickException(exception,GetMagickModule(),
-           OptionError,"UnableToAcessPath","%s",p);
+           OptionError,"UnableToAccessPath","%s",p);
        return((char *) NULL);
      }
      return(FileToString(p,~0,exception));
@@ -2968,7 +3006,7 @@ MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
         q=interpret_text+strlen(interpret_text);
       }
     /*
-      Look for percent escapes, (and handle other specials)
+      Look for the various escapes, (and handle other specials)
     */
     switch (*p) {
       case '\\':
@@ -2998,11 +3036,11 @@ MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
         }
         continue; /* never reached! */
       case '&':
-        if (LocaleNCompare("&lt;",p+1,4) != 0)
+        if (LocaleNCompare("&lt;",p,4) == 0)
           *q++='<', p+=3;
-        else if (LocaleNCompare("&gt;",p+1,4) != 0)
+        else if (LocaleNCompare("&gt;",p,4) == 0)
           *q++='>', p+=3;
-        else if (LocaleNCompare("&amp;",p+1,5) != 0)
+        else if (LocaleNCompare("&amp;",p,5) == 0)
           *q++='&', p+=4;
         else
           *q++=(*p);
@@ -3013,28 +3051,31 @@ MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
         *q++=(*p);  /* any thing else is 'as normal' */
         continue;
     }
+    p++; /* advance beyond the percent */
 
     /*
-      Doubled Percent
+      Doubled Percent - or percent at end of string
     */
-    if ( *(p+1) == '%' ) {
-        *q++=(*p);
-        p++;
-    }
+    if ( *p == '\0' )
+       p--;
+    if ( *p == '%' ) {
+        *q++='%';
+        continue;
+      }
 
     /*
-      Single letter escapes
+      Single letter escapes  %c
     */
-    if ( *(p+1) != '[' ) {
+    if ( *p != '[' ) {
       const char
         *value;
 
       /* But only if not preceeded by a number! */
       if ( IfMagickTrue(number) ) {
-        *q++=(*p); /* do NOT substitute the percent */
+        *q++='%'; /* do NOT substitute the percent */
+        p--;      /* back up one */
         continue;
       }
-      p++;
       value=GetMagickPropertyLetter(image_info,image,*p, exception);
       if (value != (char *) NULL) {
         length=strlen(value);
@@ -3043,25 +3084,21 @@ MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
             extent+=length;
             interpret_text=(char *) ResizeQuantumMemory(interpret_text,
               extent+MaxTextExtent,sizeof(*interpret_text));
-            if (interpret_text == (char *) NULL) {
-              value=DestroyString((char *)value);
+            if (interpret_text == (char *) NULL)
               return((char *)NULL);
-            }
             q=interpret_text+strlen(interpret_text);
           }
         (void) CopyMagickString(q,value,extent);
         q+=length;
-        value=DestroyString((char *)value); /* must be destoryed */
-      }
-      else {
-        (void) ThrowMagickException(exception,GetMagickModule(),
-            OptionWarning,"UnknownImageProperty","\"%%%c\"",*p);
+        continue;
       }
+      (void) ThrowMagickException(exception,GetMagickModule(),
+          OptionWarning,"UnknownImageProperty","\"%%%c\"",*p);
       continue;
     }
 
     /*
-      Braced Percent Escape
+      Braced Percent Escape  %[...]
     */
     {
       char
@@ -3078,7 +3115,7 @@ MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
         depth;
 
       /* get the string framed by the %[...] */
-      p+=2;  /* advance p to just inside the opening brace */
+      p++;  /* advance p to just inside the opening brace */
       depth=1;
       if ( *p == ']' ) {
         (void) ThrowMagickException(exception,GetMagickModule(),
@@ -3111,13 +3148,15 @@ MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
           pattern[64] = '\0';
         }
         (void) ThrowMagickException(exception,GetMagickModule(),
-            OptionError,"UnbalancedBraces","\"%%[%s]\"",pattern);
-        break; /* exit loop */
+            OptionError,"UnbalancedBraces","\"%%[%s\"",pattern);
+        interpret_text=DestroyString(interpret_text);
+        return((char *)NULL);
       }
 
       /*
-        Special Properity Prefixes
+        Special Property Prefixes
         such as: %[exif:...] %[fx:...] %[pixel:...]
+        Otherwise a free-form property string
       */
       value=GetImageProperty(image,pattern,exception);
       if (value != (const char *) NULL)
@@ -3137,7 +3176,7 @@ MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
           continue;
         }
       /*
-        Handle properity 'glob' patterns
+        Handle property 'glob' patterns
         Such as:  %[*]   %[user:array_??]  %[filename:e*]
       */
       if( IfMagickTrue(IsGlob(pattern)) )
@@ -3183,19 +3222,16 @@ MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
               extent+=length;
               interpret_text=(char *) ResizeQuantumMemory(interpret_text,
                 extent+MaxTextExtent,sizeof(*interpret_text));
-              if (interpret_text == (char *) NULL) {
-                value=DestroyString((char *)value);
+              if (interpret_text == (char *) NULL)
                 return((char *)NULL);
-              }
               q=interpret_text+strlen(interpret_text);
             }
           (void) CopyMagickString(q,value,extent);
           q+=length;
-          value=DestroyString((char *)value); /* must be destoryed */
           continue;
         }
       /*
-        Look for a per-image Artifact (escaped option)
+        Look for a per-image Artifact (user option, post-interpreted)
       */
       value=GetImageArtifact(image,pattern);
       if (value != (char *) NULL)
@@ -3215,7 +3251,7 @@ MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
           continue;
         }
       /*
-        Look for option of this name (should never match in CLI usage)
+        Look for user option of this name (should never match in CLI usage)
       */
       if (image_info != (ImageInfo *) NULL) {
         value=GetImageOption(image_info,pattern);
@@ -3269,6 +3305,9 @@ MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
 %  RemoveImageProperty() removes a property from the image and returns its
 %  value.
 %
+%  In this case the ConstantString() value returned should be freed by the
+%  caller when finished.
+%
 %  The format of the RemoveImageProperty method is:
 %
 %      char *RemoveImageProperty(Image *image,const char *property)
@@ -3345,10 +3384,10 @@ MagickExport void ResetImagePropertyIterator(const Image *image)
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  SetImageProperty() saves teh given string value either to specific known
-%  attribute or to a freeform properity string.
+%  SetImageProperty() saves the given string value either to specific known
+%  attribute or to a freeform property string.
 %
-%  Attempting to set a properity that is normally calculated will produce
+%  Attempting to set a property that is normally calculated will produce
 %  an exception.
 %
 %  The format of the SetImageProperty method is:
@@ -3381,23 +3420,28 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
   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);
-  if ((value == (const char *) NULL) || (*value == '\0'))
+
+  /* Delete property if NULL --  empty string values are valid! */
+  if ((value == (const char *) NULL))
     return(DeleteImageProperty(image,property));
   status=MagickTrue;
 
+  /* Do not 'set' single letter properties - read only shorthand */
   if (strlen(property) <= 1)
     {
       (void) ThrowMagickException(exception,GetMagickModule(),
           OptionError,"SetReadOnlyProperty","'%s'",property);
       return(MagickFalse);
     }
-  /* FUTURE: These should produce 'illegal settings'
-     + test for binary chars in name,
-     + first letter must be a alphabetic
-     + special prefix
+
+  /* FUTURE: These should produce a 'illegal settings' error
+     + binary chars in property key
+     + single letter property keys (read only)
+     + known special prefixes (read only, they don't get saved!)
   */
 
   switch (*property)
@@ -3405,7 +3449,7 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
     case 'B':
     case 'b':
     {
-      if (LocaleCompare(property,"background") == 0)
+      if (LocaleCompare("background",property) == 0)
         {
           (void) QueryColorCompliance(value,AllCompliance,
             &image->background_color,exception);
@@ -3419,14 +3463,14 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
     case 'C':
     case 'c':
     {
-      if (LocaleCompare(property,"channels") == 0)
+      if (LocaleCompare("channels",property) == 0)
         {
           (void) ThrowMagickException(exception,GetMagickModule(),
                OptionError,"SetReadOnlyProperty","'%s'",property);
           status=MagickFalse;
           break;
         }
-      if (LocaleCompare(property,"colorspace") == 0)
+      if (LocaleCompare("colorspace",property) == 0)
         {
           ssize_t
             colorspace;
@@ -3435,11 +3479,30 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
             value);
           if (colorspace < 0)
             break;
-          (void) SetImageColorspace(image,(ColorspaceType) colorspace,
-            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;
+            }
           break;
         }
-      if (LocaleCompare(property,"compose") == 0)
+      if (LocaleCompare("compose",property) == 0)
         {
           ssize_t
             compose;
@@ -3450,7 +3513,7 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
           image->compose=(CompositeOperator) compose;
           break;
         }
-      if (LocaleCompare(property,"compress") == 0)
+      if (LocaleCompare("compress",property) == 0)
         {
           ssize_t
             compression;
@@ -3462,7 +3525,7 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
           image->compression=(CompressionType) compression;
           break;
         }
-      if (LocaleCompare(property,"copyright") == 0)
+      if (LocaleCompare("copyright",property) == 0)
         {
           (void) ThrowMagickException(exception,GetMagickModule(),
                OptionError,"SetReadOnlyProperty","'%s'",property);
@@ -3476,7 +3539,7 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
     case 'D':
     case 'd':
     {
-      if (LocaleCompare(property,"delay") == 0)
+      if (LocaleCompare("delay",property) == 0)
         {
           GeometryInfo
             geometry_info;
@@ -3500,7 +3563,7 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
             image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
           break;
         }
-      if (LocaleCompare(property,"density") == 0)
+      if (LocaleCompare("density",property) == 0)
         {
           GeometryInfo
             geometry_info;
@@ -3511,12 +3574,12 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
           if ((flags & SigmaValue) == 0)
             image->resolution.y=image->resolution.x;
         }
-      if (LocaleCompare(property,"depth") == 0)
+      if (LocaleCompare("depth",property) == 0)
         {
           image->depth=StringToUnsignedLong(value);
           break;
         }
-      if (LocaleCompare(property,"dispose") == 0)
+      if (LocaleCompare("dispose",property) == 0)
         {
           ssize_t
             dispose;
@@ -3534,7 +3597,12 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
     case 'G':
     case 'g':
     {
-      if (LocaleCompare(property,"gravity") == 0)
+      if (LocaleCompare("gamma",property) == 0)
+        {
+          image->gamma=StringToDouble(value,(char **) NULL);
+          break;
+        }
+      if (LocaleCompare("gravity",property) == 0)
         {
           ssize_t
             gravity;
@@ -3551,7 +3619,7 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
     }
     case 'H':
     case 'h':
-      if (LocaleCompare(property,"height") == 0)
+      if (LocaleCompare("height",property) == 0)
         {
           (void) ThrowMagickException(exception,GetMagickModule(),
                OptionError,"SetReadOnlyProperty","'%s'",property);
@@ -3561,7 +3629,7 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
     case 'I':
     case 'i':
     {
-      if (LocaleCompare(property,"intent") == 0)
+      if (LocaleCompare("intent",property) == 0)
         {
           ssize_t
             rendering_intent;
@@ -3573,7 +3641,7 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
           image->rendering_intent=(RenderingIntent) rendering_intent;
           break;
         }
-      if (LocaleCompare(property,"interpolate") == 0)
+      if (LocaleCompare("interpolate",property) == 0)
         {
           ssize_t
             interpolate;
@@ -3591,7 +3659,7 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
     }
     case 'K':
     case 'k':
-      if (LocaleCompare(property,"kurtosis") == 0)
+      if (LocaleCompare("kurtosis",property) == 0)
         {
           (void) ThrowMagickException(exception,GetMagickModule(),
                OptionError,"SetReadOnlyProperty","'%s'",property);
@@ -3601,7 +3669,7 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
     case 'L':
     case 'l':
     {
-      if (LocaleCompare(property,"loop") == 0)
+      if (LocaleCompare("loop",property) == 0)
         {
           image->iterations=StringToUnsignedLong(value);
           break;
@@ -3612,20 +3680,20 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
     }
     case 'M':
     case 'm':
-      if ( (LocaleCompare(property,"magick") == 0) ||
-           (LocaleCompare(property,"max") == 0) ||
-           (LocaleCompare(property,"mean") == 0) ||
-           (LocaleCompare(property,"min") == 0) ||
-           (LocaleCompare(property,"min") == 0) )
-        {
-          (void) ThrowMagickException(exception,GetMagickModule(),
-               OptionError,"SetReadOnlyProperty","'%s'",property);
+      if ( (LocaleCompare("magick",property) == 0) ||
+           (LocaleCompare("max",property) == 0) ||
+           (LocaleCompare("mean",property) == 0) ||
+           (LocaleCompare("min",property) == 0) ||
+           (LocaleCompare("min",property) == 0) )
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+             "SetReadOnlyProperty","'%s'",property);
           status=MagickFalse;
           break;
         }
     case 'O':
     case 'o':
-      if (LocaleCompare(property,"opaque") == 0)
+      if (LocaleCompare("opaque",property) == 0)
         {
           (void) ThrowMagickException(exception,GetMagickModule(),
                OptionError,"SetReadOnlyProperty","'%s'",property);
@@ -3635,7 +3703,7 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
     case 'P':
     case 'p':
     {
-      if (LocaleCompare(property,"page") == 0)
+      if (LocaleCompare("page",property) == 0)
         {
           char
             *geometry;
@@ -3645,7 +3713,7 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
           geometry=DestroyString(geometry);
           break;
         }
-      if (LocaleCompare(property,"profile") == 0)
+      if (LocaleCompare("profile",property) == 0)
         {
           ImageInfo
             *image_info;
@@ -3669,7 +3737,7 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
     case 'R':
     case 'r':
     {
-      if (LocaleCompare(property,"rendering-intent") == 0)
+      if (LocaleCompare("rendering-intent",property) == 0)
         {
           ssize_t
             rendering_intent;
@@ -3688,10 +3756,10 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
     }
     case 'S':
     case 's':
-      if ( (LocaleCompare(property,"size") == 0) ||
-           (LocaleCompare(property,"skewness") == 0) ||
-           (LocaleCompare(property,"scenes") == 0) ||
-           (LocaleCompare(property,"standard-deviation") == 0) )
+      if ( (LocaleCompare("size",property) == 0) ||
+           (LocaleCompare("skewness",property) == 0) ||
+           (LocaleCompare("scenes",property) == 0) ||
+           (LocaleCompare("standard-deviation",property) == 0) )
         {
           (void) ThrowMagickException(exception,GetMagickModule(),
                OptionError,"SetReadOnlyProperty","'%s'",property);
@@ -3701,7 +3769,7 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
     case 'T':
     case 't':
     {
-      if (LocaleCompare(property,"tile-offset") == 0)
+      if (LocaleCompare("tile-offset",property) == 0)
         {
           char
             *geometry;
@@ -3718,7 +3786,7 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
     case 'U':
     case 'u':
     {
-      if (LocaleCompare(property,"units") == 0)
+      if (LocaleCompare("units",property) == 0)
         {
           ssize_t
             units;
@@ -3735,7 +3803,7 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
     }
     case 'V':
     case 'v':
-      if (LocaleCompare(property,"version") == 0)
+      if (LocaleCompare("version",property) == 0)
         {
           (void) ThrowMagickException(exception,GetMagickModule(),
                OptionError,"SetReadOnlyProperty","'%s'",property);
@@ -3744,7 +3812,7 @@ MagickExport MagickBooleanType SetImageProperty(Image *image,
         }
     case 'W':
     case 'w':
-      if (LocaleCompare(property,"width") == 0)
+      if (LocaleCompare("width",property) == 0)
         {
           (void) ThrowMagickException(exception,GetMagickModule(),
                OptionError,"SetReadOnlyProperty","'%s'",property);