]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/geometry.c
Added caNv, eXIf, and pHYs to the list of PNG chunks to be removed
[imagemagick] / MagickCore / geometry.c
index 0a6f4dc57efdaa3d31db615e29376b0735c77265..a9480506c4a0a00592d3ea687da4529017c95156 100644 (file)
 %                       MagickCore Geometry Methods                           %
 %                                                                             %
 %                             Software Design                                 %
-%                               John Cristy                                   %
+%                                  Cristy                                     %
 %                              January 2003                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2017 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  %
 %  obtain a copy of the License at                                            %
 %                                                                             %
-%    http://www.imagemagick.org/script/license.php                            %
+%    https://www.imagemagick.org/script/license.php                           %
 %                                                                             %
 %  Unless required by applicable law or agreed to in writing, software        %
 %  distributed under the License is distributed on an "AS IS" BASIS,          %
@@ -45,6 +45,7 @@
 #include "MagickCore/exception.h"
 #include "MagickCore/exception-private.h"
 #include "MagickCore/geometry.h"
+#include "MagickCore/image-private.h"
 #include "MagickCore/memory_.h"
 #include "MagickCore/string_.h"
 #include "MagickCore/string-private.h"
 %  whether the x or y values are negative.  In addition, there are flags to
 %  report any meta characters (%, !, <, or >).
 %
+%  The value must form a proper geometry style specification of WxH+X+Y
+%  of integers only, and values can not be separated by comma, colon, or
+%  slash charcaters.  See ParseGeometry() below.
+%
+%  Offsets may be prefixed by multiple signs to make offset string
+%  substitutions easier to handle from shell scripts.
+%  For example: "-10-10", "-+10-+10", or "+-10+-10" will generate negtive
+%  offsets, while "+10+10", "++10++10", or "--10--10" will generate positive
+%  offsets.
+%
 %  The format of the GetGeometry method is:
 %
 %      MagickStatusType GetGeometry(const char *geometry,ssize_t *x,ssize_t *y,
@@ -87,7 +98,7 @@ MagickExport MagickStatusType GetGeometry(const char *geometry,ssize_t *x,
 {
   char
     *p,
-    pedantic_geometry[MaxTextExtent],
+    pedantic_geometry[MagickPathExtent],
     *q;
 
   double
@@ -105,14 +116,14 @@ MagickExport MagickStatusType GetGeometry(const char *geometry,ssize_t *x,
   flags=NoValue;
   if ((geometry == (char *) NULL) || (*geometry == '\0'))
     return(flags);
-  if (strlen(geometry) >= (MaxTextExtent-1))
+  if (strlen(geometry) >= (MagickPathExtent-1))
     return(flags);
-  (void) CopyMagickString(pedantic_geometry,geometry,MaxTextExtent);
+  (void) CopyMagickString(pedantic_geometry,geometry,MagickPathExtent);
   for (p=pedantic_geometry; *p != '\0'; )
   {
     if (isspace((int) ((unsigned char) *p)) != 0)
       {
-        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        (void) CopyMagickString(p,p+1,MagickPathExtent);
         continue;
       }
     c=(int)*p;
@@ -121,43 +132,50 @@ MagickExport MagickStatusType GetGeometry(const char *geometry,ssize_t *x,
       case '%':
       {
         flags|=PercentValue;
-        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        (void) CopyMagickString(p,p+1,MagickPathExtent);
         break;
       }
       case '!':
       {
         flags|=AspectValue;
-        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        (void) CopyMagickString(p,p+1,MagickPathExtent);
         break;
       }
       case '<':
       {
         flags|=LessValue;
-        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        (void) CopyMagickString(p,p+1,MagickPathExtent);
         break;
       }
       case '>':
       {
         flags|=GreaterValue;
-        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        (void) CopyMagickString(p,p+1,MagickPathExtent);
         break;
       }
       case '^':
       {
         flags|=MinimumValue;
-        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        (void) CopyMagickString(p,p+1,MagickPathExtent);
         break;
       }
       case '@':
       {
         flags|=AreaValue;
-        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        (void) CopyMagickString(p,p+1,MagickPathExtent);
         break;
       }
       case '(':
       case ')':
       {
-        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        (void) CopyMagickString(p,p+1,MagickPathExtent);
+        break;
+      }
+      case 'x':
+      case 'X':
+      {
+        flags|=SeparatorValue;
+        p++;
         break;
       }
       case '-':
@@ -174,9 +192,9 @@ MagickExport MagickStatusType GetGeometry(const char *geometry,ssize_t *x,
       case '7':
       case '8':
       case '9':
-      case 'x':
-      case 'X':
       case 215:
+      case 'e':
+      case 'E':
       {
         p++;
         break;
@@ -196,33 +214,43 @@ MagickExport MagickStatusType GetGeometry(const char *geometry,ssize_t *x,
   (void) value;
   if (LocaleNCompare(p,"0x",2) == 0)
     value=(double) strtol(p,&q,10);
-  c=(int) ((unsigned char) *q);
-  if ((c == 215) || (*q == 'x') || (*q == 'X') || (*q == '\0'))
-    {
-      /*
-        Parse width.
-      */
-      q=p;
-      if (LocaleNCompare(p,"0x",2) == 0)
-        *width=(size_t) strtol(p,&p,10);
-      else
-        *width=(size_t) floor(StringToDouble(p,&p)+0.5);
-      if (p != q)
-        flags|=WidthValue;
-    }
-  c=(int) ((unsigned char) *p);
-  if ((c == 215) || (*p == 'x') || (*p == 'X'))
+  if ((*p != '+') && (*p != '-'))
     {
-      p++;
-      if ((*p != '+') && (*p != '-'))
+      c=(int) ((unsigned char) *q);
+      if ((c == 215) || (*q == 'x') || (*q == 'X') || (*q == '\0'))
         {
           /*
-            Parse height.
+            Parse width.
           */
           q=p;
-          *height=(size_t) floor(StringToDouble(p,&p)+0.5);
+          if (width != (size_t *) NULL)
+            {
+              if (LocaleNCompare(p,"0x",2) == 0)
+                *width=(size_t) strtol(p,&p,10);
+              else
+                *width=(size_t) floor(StringToDouble(p,&p)+0.5);
+            }
           if (p != q)
-            flags|=HeightValue;
+            flags|=WidthValue;
+        }
+    }
+  if ((*p != '+') && (*p != '-'))
+    {
+      c=(int) ((unsigned char) *p);
+      if ((c == 215) || (*p == 'x') || (*p == 'X'))
+        {
+          p++;
+          if ((*p != '+') && (*p != '-'))
+            {
+              /*
+                Parse height.
+              */
+              q=p;
+              if (height != (size_t *) NULL)
+                *height=(size_t) floor(StringToDouble(p,&p)+0.5);
+              if (p != q)
+                flags|=HeightValue;
+            }
         }
     }
   if ((*p == '+') || (*p == '-'))
@@ -230,25 +258,66 @@ MagickExport MagickStatusType GetGeometry(const char *geometry,ssize_t *x,
       /*
         Parse x value.
       */
-      if (*p == '-')
-        flags|=XNegative;
+      while ((*p == '+') || (*p == '-'))
+      {
+        if (*p == '-')
+          flags^=XNegative;  /* negate sign */
+        p++;
+      }
       q=p;
-      *x=(ssize_t) ceil(StringToDouble(p,&p)-0.5);
+      if (x != (ssize_t *) NULL)
+        *x=(ssize_t) ceil(StringToDouble(p,&p)-0.5);
       if (p != q)
-        flags|=XValue;
-      if ((*p == '+') || (*p == '-'))
         {
-          /*
-            Parse y value.
-          */
-          if (*p == '-')
-            flags|=YNegative;
-          q=p;
-          *y=(ssize_t) ceil(StringToDouble(p,&p)-0.5);
-          if (p != q)
-            flags|=YValue;
+          flags|=XValue;
+          if (((flags & XNegative) != 0) && (x != (ssize_t *) NULL))
+            *x=(-*x);
+        }
+    }
+  if ((*p == '+') || (*p == '-'))
+    {
+      /*
+        Parse y value.
+      */
+      while ((*p == '+') || (*p == '-'))
+      {
+        if (*p == '-')
+          flags^=YNegative;  /* negate sign */
+        p++;
+      }
+      q=p;
+      if (y != (ssize_t *) NULL)
+        *y=(ssize_t) ceil(StringToDouble(p,&p)-0.5);
+      if (p != q)
+        {
+          flags|=YValue;
+          if (((flags & YNegative) != 0) && (y != (ssize_t *) NULL))
+            *y=(-*y);
         }
     }
+  if ((flags & PercentValue) != 0)
+    {
+      if (((flags & SeparatorValue) == 0) && ((flags & HeightValue) == 0))
+        {
+          if ((height != (size_t *) NULL) && (width != (size_t *) NULL))
+            *height=(*width);
+          flags|=HeightValue;
+        }
+      if (((flags & SeparatorValue) != 0) && ((flags & WidthValue) == 0) &&
+          (height != (size_t *) NULL) && (width != (size_t *) NULL))
+            *width=(*height);
+    }
+#if 0
+  /* Debugging Geometry */
+  (void) fprintf(stderr,"GetGeometry...\n");
+  (void) fprintf(stderr,"Input: %s\n",geometry);
+  (void) fprintf(stderr,"Flags: %c %c %s %s\n",
+    (flags & WidthValue) ? 'W' : ' ',(flags & HeightValue) ? 'H' : ' ',
+    (flags & XValue) ? ((flags & XNegative) ? "-X" : "+X") : "  ",
+    (flags & YValue) ? ((flags & YNegative) ? "-Y" : "+Y") : "  ");
+  (void) fprintf(stderr,"Geometry: %ldx%ld%+ld%+ld\n",(long) *width,(long)
+    *height,(long) *x,(long) *y);
+#endif
   return(flags);
 }
 \f
@@ -279,118 +348,136 @@ MagickExport MagickStatusType GetGeometry(const char *geometry,ssize_t *x,
 */
 MagickExport char *GetPageGeometry(const char *page_geometry)
 {
-  static const char
-    *PageSizes[][2]=
+#define MagickPageSize(name,geometry) { (name), sizeof(name)-1, (geometry) }
+
+  typedef struct _PageInfo
+  {
+    const char
+      *name;
+
+    size_t
+      extent;
+
+    const char
+      *geometry;
+  } PageInfo;
+
+  static const PageInfo
+    PageSizes[] =
     {
-      { "4x6",  "288x432" },
-      { "5x7",  "360x504" },
-      { "7x9",  "504x648" },
-      { "8x10", "576x720" },
-      { "9x11",  "648x792" },
-      { "9x12",  "648x864" },
-      { "10x13",  "720x936" },
-      { "10x14",  "720x1008" },
-      { "11x17",  "792x1224" },
-      { "a0",  "2384x3370" },
-      { "a1",  "1684x2384" },
-      { "a10", "73x105" },
-      { "a2",  "1191x1684" },
-      { "a3",  "842x1191" },
-      { "a4",  "595x842" },
-      { "a4smaLL", "595x842" },
-      { "a5",  "420x595" },
-      { "a6",  "297x420" },
-      { "a7",  "210x297" },
-      { "a8",  "148x210" },
-      { "a9",  "105x148" },
-      { "archa", "648x864" },
-      { "archb", "864x1296" },
-      { "archC", "1296x1728" },
-      { "archd", "1728x2592" },
-      { "arche", "2592x3456" },
-      { "b0",  "2920x4127" },
-      { "b1",  "2064x2920" },
-      { "b10", "91x127" },
-      { "b2",  "1460x2064" },
-      { "b3",  "1032x1460" },
-      { "b4",  "729x1032" },
-      { "b5",  "516x729" },
-      { "b6",  "363x516" },
-      { "b7",  "258x363" },
-      { "b8",  "181x258" },
-      { "b9",  "127x181" },
-      { "c0",  "2599x3676" },
-      { "c1",  "1837x2599" },
-      { "c2",  "1298x1837" },
-      { "c3",  "918x1296" },
-      { "c4",  "649x918" },
-      { "c5",  "459x649" },
-      { "c6",  "323x459" },
-      { "c7",  "230x323" },
-      { "executive", "540x720" },
-      { "flsa", "612x936" },
-      { "flse", "612x936" },
-      { "folio",  "612x936" },
-      { "halfletter", "396x612" },
-      { "isob0", "2835x4008" },
-      { "isob1", "2004x2835" },
-      { "isob10", "88x125" },
-      { "isob2", "1417x2004" },
-      { "isob3", "1001x1417" },
-      { "isob4", "709x1001" },
-      { "isob5", "499x709" },
-      { "isob6", "354x499" },
-      { "isob7", "249x354" },
-      { "isob8", "176x249" },
-      { "isob9", "125x176" },
-      { "jisb0", "1030x1456" },
-      { "jisb1", "728x1030" },
-      { "jisb2", "515x728" },
-      { "jisb3", "364x515" },
-      { "jisb4", "257x364" },
-      { "jisb5", "182x257" },
-      { "jisb6", "128x182" },
-      { "ledger",  "1224x792" },
-      { "legal",  "612x1008" },
-      { "letter", "612x792" },
-      { "lettersmaLL",  "612x792" },
-      { "quarto",  "610x780" },
-      { "statement",  "396x612" },
-      { "tabloid",  "792x1224" },
-      { (char *) NULL, (char *) NULL }
+      MagickPageSize("4x6", "288x432"),
+      MagickPageSize("5x7", "360x504"),
+      MagickPageSize("7x9", "504x648"),
+      MagickPageSize("8x10", "576x720"),
+      MagickPageSize("9x11", "648x792"),
+      MagickPageSize("9x12", "648x864"),
+      MagickPageSize("10x13", "720x936"),
+      MagickPageSize("10x14", "720x1008"),
+      MagickPageSize("11x17", "792x1224"),
+      MagickPageSize("a0", "2384x3370"),
+      MagickPageSize("a1", "1684x2384"),
+      MagickPageSize("a10", "73x105"),
+      MagickPageSize("a2", "1191x1684"),
+      MagickPageSize("a3", "842x1191"),
+      MagickPageSize("a4", "595x842"),
+      MagickPageSize("a4small", "595x842"),
+      MagickPageSize("a5", "420x595"),
+      MagickPageSize("a6", "297x420"),
+      MagickPageSize("a7", "210x297"),
+      MagickPageSize("a8", "148x210"),
+      MagickPageSize("a9", "105x148"),
+      MagickPageSize("archa", "648x864"),
+      MagickPageSize("archb", "864x1296"),
+      MagickPageSize("archC", "1296x1728"),
+      MagickPageSize("archd", "1728x2592"),
+      MagickPageSize("arche", "2592x3456"),
+      MagickPageSize("b0", "2920x4127"),
+      MagickPageSize("b1", "2064x2920"),
+      MagickPageSize("b10", "91x127"),
+      MagickPageSize("b2", "1460x2064"),
+      MagickPageSize("b3", "1032x1460"),
+      MagickPageSize("b4", "729x1032"),
+      MagickPageSize("b5", "516x729"),
+      MagickPageSize("b6", "363x516"),
+      MagickPageSize("b7", "258x363"),
+      MagickPageSize("b8", "181x258"),
+      MagickPageSize("b9", "127x181"),
+      MagickPageSize("c0", "2599x3676"),
+      MagickPageSize("c1", "1837x2599"),
+      MagickPageSize("c2", "1298x1837"),
+      MagickPageSize("c3", "918x1296"),
+      MagickPageSize("c4", "649x918"),
+      MagickPageSize("c5", "459x649"),
+      MagickPageSize("c6", "323x459"),
+      MagickPageSize("c7", "230x323"),
+      MagickPageSize("executive", "540x720"),
+      MagickPageSize("flsa", "612x936"),
+      MagickPageSize("flse", "612x936"),
+      MagickPageSize("folio", "612x936"),
+      MagickPageSize("halfletter", "396x612"),
+      MagickPageSize("isob0", "2835x4008"),
+      MagickPageSize("isob1", "2004x2835"),
+      MagickPageSize("isob10", "88x125"),
+      MagickPageSize("isob2", "1417x2004"),
+      MagickPageSize("isob3", "1001x1417"),
+      MagickPageSize("isob4", "709x1001"),
+      MagickPageSize("isob5", "499x709"),
+      MagickPageSize("isob6", "354x499"),
+      MagickPageSize("isob7", "249x354"),
+      MagickPageSize("isob8", "176x249"),
+      MagickPageSize("isob9", "125x176"),
+      MagickPageSize("jisb0", "1030x1456"),
+      MagickPageSize("jisb1", "728x1030"),
+      MagickPageSize("jisb2", "515x728"),
+      MagickPageSize("jisb3", "364x515"),
+      MagickPageSize("jisb4", "257x364"),
+      MagickPageSize("jisb5", "182x257"),
+      MagickPageSize("jisb6", "128x182"),
+      MagickPageSize("ledger", "1224x792"),
+      MagickPageSize("legal", "612x1008"),
+      MagickPageSize("letter", "612x792"),
+      MagickPageSize("lettersmall", "612x792"),
+      MagickPageSize("quarto", "610x780"),
+      MagickPageSize("statement", "396x612"),
+      MagickPageSize("tabloid", "792x1224")
     };
 
   char
-    *page;
+    page[MaxTextExtent];
 
   register ssize_t
     i;
 
   assert(page_geometry != (char *) NULL);
   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",page_geometry);
-  page=AcquireString(page_geometry);
-  for (i=0; *PageSizes[i] != (char *) NULL; i++)
-    if (LocaleNCompare(PageSizes[i][0],page,strlen(PageSizes[i][0])) == 0)
+  CopyMagickString(page,page_geometry,MaxTextExtent);
+  for (i=0; i < (ssize_t) (sizeof(PageSizes)/sizeof(PageSizes[0])); i++)
+  {
+    int
+      status;
+    
+    status=LocaleNCompare(PageSizes[i].name,page_geometry,PageSizes[i].extent);
+    if (status == 0)
       {
-        RectangleInfo
-          geometry;
-
         MagickStatusType
           flags;
 
+        RectangleInfo
+          geometry;
+
         /*
           Replace mneumonic with the equivalent size in dots-per-inch.
         */
-        (void) CopyMagickString(page,PageSizes[i][1],MaxTextExtent);
-        (void) ConcatenateMagickString(page,page_geometry+
-          strlen(PageSizes[i][0]),MaxTextExtent);
+        (void) FormatLocaleString(page,MaxTextExtent,"%s%.80s",
+          PageSizes[i].geometry,page_geometry+PageSizes[i].extent);
         flags=GetGeometry(page,&geometry.x,&geometry.y,&geometry.width,
           &geometry.height);
         if ((flags & GreaterValue) == 0)
           (void) ConcatenateMagickString(page,">",MaxTextExtent);
         break;
       }
-  return(page);
+  }
+  return(AcquireString(page));
 }
 \f
 /*
@@ -400,7 +487,8 @@ MagickExport char *GetPageGeometry(const char *page_geometry)
 %                                                                             %
 %   G r a v i t y A d j u s t G e o m e t r y                                 %
 %                                                                             %
-%                                                                             % %                                                                             %
+%                                                                             %
+%                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
 %  GravityAdjustGeometry() adjusts the offset of a region with regard to the
@@ -442,7 +530,6 @@ MagickExport void GravityAdjustGeometry(const size_t width,
     case NorthGravity:
     case SouthGravity:
     case CenterGravity:
-    case StaticGravity:
     {
       region->x+=(ssize_t) (width/2-region->width/2);
       break;
@@ -466,7 +553,6 @@ MagickExport void GravityAdjustGeometry(const size_t width,
     case EastGravity:
     case WestGravity:
     case CenterGravity:
-    case StaticGravity:
     {
       region->y+=(ssize_t) (height/2-region->height/2);
       break;
@@ -642,7 +728,7 @@ MagickExport MagickStatusType ParseAffineGeometry(const char *geometry,
   AffineMatrix *affine_matrix,ExceptionInfo *exception)
 {
   char
-    token[MaxTextExtent];
+    token[MagickPathExtent];
 
   const char
     *p;
@@ -661,9 +747,9 @@ MagickExport MagickStatusType ParseAffineGeometry(const char *geometry,
   p=(char *) geometry;
   for (i=0; (*p != '\0') && (i < 6); i++)
   {
-    GetMagickToken(p,&p,token);
+    GetNextToken(p,&p,MagickPathExtent,token);
     if (*token == ',')
-      GetMagickToken(p,&p,token);
+      GetNextToken(p,&p,MagickPathExtent,token);
     switch (i)
     {
       case 0:
@@ -700,8 +786,8 @@ MagickExport MagickStatusType ParseAffineGeometry(const char *geometry,
       }
     }
   }
-  determinant=(affine_matrix->sx*affine_matrix->sy
-                 - affine_matrix->rx*affine_matrix->ry);
+  determinant=(affine_matrix->sx*affine_matrix->sy-affine_matrix->rx*
+    affine_matrix->ry);
   if (fabs(determinant) < MagickEpsilon)
     (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
       "InvalidArgument","'%s' : 'Indeterminate Matrix'",geometry);
@@ -728,6 +814,13 @@ MagickExport MagickStatusType ParseAffineGeometry(const char *geometry,
 %  and ^) flags present. It does not report the location of the percentage
 %  relative to the values.
 %
+%  Values may also be separated by commas, colons, or slashes, and offsets.
+%  Offsets may be prefixed by multiple signs to make offset string
+%  substitutions easier to handle from shell scripts.
+%  For example: "-10-10", "-+10-+10", or "+-10+-10" will generate negtive
+%  offsets, while "+10+10", "++10++10", or "--10--10" will generate positive
+%  offsets.
+%
 %  The format of the ParseGeometry method is:
 %
 %      MagickStatusType ParseGeometry(const char *geometry,
@@ -745,12 +838,15 @@ MagickExport MagickStatusType ParseGeometry(const char *geometry,
 {
   char
     *p,
-    pedantic_geometry[MaxTextExtent],
+    pedantic_geometry[MagickPathExtent],
     *q;
 
   double
     value;
 
+  GeometryInfo
+    coordinate;
+
   int
     c;
 
@@ -764,59 +860,80 @@ MagickExport MagickStatusType ParseGeometry(const char *geometry,
   flags=NoValue;
   if ((geometry == (char *) NULL) || (*geometry == '\0'))
     return(flags);
-  if (strlen(geometry) >= (MaxTextExtent-1))
+  if (strlen(geometry) >= (MagickPathExtent-1))
     return(flags);
-  (void) CopyMagickString(pedantic_geometry,geometry,MaxTextExtent);
+  c=sscanf(geometry,"%lf%*[ ,]%lf%*[ ,]%lf%*[ ,]%lf",&coordinate.rho,
+    &coordinate.sigma,&coordinate.xi,&coordinate.psi);
+  if (c == 4)
+    {
+      /*
+        Special case: coordinate (e.g. 0,0 255,255).
+      */
+      geometry_info->rho=coordinate.rho;
+      geometry_info->sigma=coordinate.sigma;
+      geometry_info->xi=coordinate.xi;
+      geometry_info->psi=coordinate.psi;
+      flags|=RhoValue | SigmaValue | XiValue | PsiValue;
+      return(flags);
+    }
+  (void) CopyMagickString(pedantic_geometry,geometry,MagickPathExtent);
   for (p=pedantic_geometry; *p != '\0'; )
   {
-    if (isspace((int) ((unsigned char) *p)) != 0)
+    c=(int) ((unsigned char) *p);
+    if (isspace(c) != 0)
       {
-        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        (void) CopyMagickString(p,p+1,MagickPathExtent);
         continue;
       }
-    c=(int) ((unsigned char) *p);
     switch (c)
     {
       case '%':
       {
         flags|=PercentValue;
-        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        (void) CopyMagickString(p,p+1,MagickPathExtent);
         break;
       }
       case '!':
       {
         flags|=AspectValue;
-        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        (void) CopyMagickString(p,p+1,MagickPathExtent);
         break;
       }
       case '<':
       {
         flags|=LessValue;
-        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        (void) CopyMagickString(p,p+1,MagickPathExtent);
         break;
       }
       case '>':
       {
         flags|=GreaterValue;
-        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        (void) CopyMagickString(p,p+1,MagickPathExtent);
         break;
       }
       case '^':
       {
         flags|=MinimumValue;
-        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        (void) CopyMagickString(p,p+1,MagickPathExtent);
         break;
       }
       case '@':
       {
         flags|=AreaValue;
-        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        (void) CopyMagickString(p,p+1,MagickPathExtent);
         break;
       }
       case '(':
       case ')':
       {
-        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        (void) CopyMagickString(p,p+1,MagickPathExtent);
+        break;
+      }
+      case 'x':
+      case 'X':
+      {
+        flags|=SeparatorValue;
+        p++;
         break;
       }
       case '-':
@@ -832,11 +949,11 @@ MagickExport MagickStatusType ParseGeometry(const char *geometry,
       case '7':
       case '8':
       case '9':
-      case 'x':
-      case 'X':
       case '/':
       case ':':
       case 215:
+      case 'e':
+      case 'E':
       {
         p++;
         break;
@@ -848,7 +965,7 @@ MagickExport MagickStatusType ParseGeometry(const char *geometry,
         break;
       }
       default:
-        return(flags);
+        return(NoValue);
     }
   }
   /*
@@ -860,7 +977,7 @@ MagickExport MagickStatusType ParseGeometry(const char *geometry,
   q=p;
   value=StringToDouble(p,&q);
   if (LocaleNCompare(p,"0x",2) == 0)
-    value=(double) strtol(p,&q,10);
+    (void) strtol(p,&q,10);
   c=(int) ((unsigned char) *q);
   if ((c == 215) || (*q == 'x') || (*q == 'X') || (*q == ',') ||
       (*q == '/') || (*q == ':') || (*q =='\0'))
@@ -910,15 +1027,21 @@ MagickExport MagickStatusType ParseGeometry(const char *geometry,
       /*
         Parse xi value.
       */
-      if ((*p == '+') || (*p == ',') || (*p == '/') || (*p == ':') )
+      if ((*p == ',') || (*p == '/') || (*p == ':') )
         p++;
+      while ((*p == '+') || (*p == '-'))
+      {
+        if (*p == '-')
+          flags^=XiNegative;  /* negate sign */
+        p++;
+      }
       q=p;
       value=StringToDouble(p,&p);
       if (p != q)
         {
           flags|=XiValue;
-          if (*q == '-')
-            flags|=XiNegative;
+          if ((flags & XiNegative) != 0)
+            value=(-value);
           geometry_info->xi=value;
         }
       while (isspace((int) ((unsigned char) *p)) != 0)
@@ -929,18 +1052,24 @@ MagickExport MagickStatusType ParseGeometry(const char *geometry,
           /*
             Parse psi value.
           */
-          if ((*p == '+') || (*p == ',') || (*p == '/') || (*p == ':'))
+          if ((*p == ',') || (*p == '/') || (*p == ':'))
             p++;
+          while ((*p == '+') || (*p == '-'))
+          {
+            if (*p == '-')
+              flags^=PsiNegative;  /* negate sign */
+            p++;
+          }
           q=p;
           value=StringToDouble(p,&p);
           if (p != q)
             {
               flags|=PsiValue;
-              if (*q == '-')
-                flags|=PsiNegative;
+              if ((flags & PsiNegative) != 0)
+                value=(-value);
               geometry_info->psi=value;
             }
-        }
+      }
       while (isspace((int) ((unsigned char) *p)) != 0)
         p++;
       if ((*p == '+') || (*p == '-') || (*p == ',') || (*p == '/') ||
@@ -949,15 +1078,21 @@ MagickExport MagickStatusType ParseGeometry(const char *geometry,
           /*
             Parse chi value.
           */
-          if ((*p == '+') || (*p == ',') || (*p == '/') || (*p == ':'))
+          if ((*p == ',') || (*p == '/') || (*p == ':'))
+            p++;
+          while ((*p == '+') || (*p == '-'))
+          {
+            if (*p == '-')
+              flags^=ChiNegative;  /* negate sign */
             p++;
+          }
           q=p;
           value=StringToDouble(p,&p);
           if (p != q)
             {
               flags|=ChiValue;
-              if (*q == '-')
-                flags|=ChiNegative;
+              if ((flags & ChiNegative) != 0)
+                value=(-value);
               geometry_info->chi=value;
             }
         }
@@ -983,6 +1118,25 @@ MagickExport MagickStatusType ParseGeometry(const char *geometry,
       flags|=SigmaValue;
       flags&=(~XiValue);
     }
+  if ((flags & PercentValue) != 0)
+    {
+      if (((flags & SeparatorValue) == 0) && ((flags & SigmaValue) == 0))
+        geometry_info->sigma=geometry_info->rho;
+      if (((flags & SeparatorValue) != 0) && ((flags & RhoValue) == 0))
+        geometry_info->rho=geometry_info->sigma;
+    }
+#if 0
+  /* Debugging Geometry */
+  (void) fprintf(stderr,"ParseGeometry...\n");
+  (void) fprintf(stderr,"Flags: %c %c %s %s %s\n",
+    (flags & RhoValue) ? 'W' : ' ',(flags & SigmaValue) ? 'H' : ' ',
+    (flags & XiValue) ? ((flags & XiNegative) ? "-X" : "+X") : "  ",
+    (flags & PsiValue) ? ((flags & PsiNegative) ? "-Y" : "+Y") : "  ",
+    (flags & ChiValue) ? ((flags & ChiNegative) ? "-Z" : "+Z") : "  ");
+  (void) fprintf(stderr,"Geometry: %lg,%lg,%lg,%lg,%lg\n",geometry_info->rho,
+    geometry_info->sigma,geometry_info->xi,geometry_info->psi,
+    geometry_info->chi);
+#endif
   return(flags);
 }
 \f
@@ -1042,7 +1196,7 @@ MagickExport MagickStatusType ParseGravityGeometry(const Image *image,
   if (flags == NoValue)
     {
       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
-        "InvalidGeometry","'%s'",geometry);
+        "InvalidGeometry","`%s'",geometry);
       return(flags);
     }
   if ((flags & PercentValue) != 0)
@@ -1106,7 +1260,7 @@ MagickExport MagickStatusType ParseGravityGeometry(const Image *image,
 %  image within the specified geometry width and height.
 %
 %  Flags are interpreted...
-%     %   geometry size is given percentage of original image size
+%     %   geometry size is given percentage of original width and height given
 %     !   do not try to preserve aspect ratio
 %     <   only enlarge images smaller that geometry
 %     >   only shrink images larger than geometry
@@ -1129,14 +1283,6 @@ MagickExport MagickStatusType ParseGravityGeometry(const Image *image,
 %
 */
 
-static inline size_t MagickMax(const size_t x,
-  const size_t y)
-{
-  if (x > y)
-    return(x);
-  return(y);
-}
-
 MagickExport MagickStatusType ParseMetaGeometry(const char *geometry,ssize_t *x,
   ssize_t *y,size_t *width,size_t *height)
 {
@@ -1170,7 +1316,7 @@ MagickExport MagickStatusType ParseMetaGeometry(const char *geometry,ssize_t *x,
   if ((flags & PercentValue) != 0)
     {
       MagickStatusType
-        flags;
+        percent_flags;
 
       PointInfo
         scale;
@@ -1178,19 +1324,15 @@ MagickExport MagickStatusType ParseMetaGeometry(const char *geometry,ssize_t *x,
       /*
         Geometry is a percentage of the image size.
       */
-      flags=ParseGeometry(geometry,&geometry_info);
+      percent_flags=ParseGeometry(geometry,&geometry_info);
       scale.x=geometry_info.rho;
-      if ((flags & RhoValue) == 0)
+      if ((percent_flags & RhoValue) == 0)
         scale.x=100.0;
       scale.y=geometry_info.sigma;
-      if ((flags & SigmaValue) == 0)
+      if ((percent_flags & SigmaValue) == 0)
         scale.y=scale.x;
       *width=(size_t) floor(scale.x*former_width/100.0+0.5);
-      if (*width == 0)
-        *width=1;
       *height=(size_t) floor(scale.y*former_height/100.0+0.5);
-      if (*height == 0)
-        *height=1;
       former_width=(*width);
       former_height=(*height);
     }
@@ -1270,14 +1412,14 @@ MagickExport MagickStatusType ParseMetaGeometry(const char *geometry,ssize_t *x,
         Geometry is a maximum area in pixels.
       */
       (void) ParseGeometry(geometry,&geometry_info);
-      area=geometry_info.rho;
+      area=geometry_info.rho+sqrt(MagickEpsilon);
       distance=sqrt((double) former_width*former_height);
-      scale.x=(double) former_width/(distance/sqrt((double) area));
-      scale.y=(double) former_height/(distance/sqrt((double) area));
+      scale.x=(double) former_width/(distance/sqrt(area));
+      scale.y=(double) former_height/(distance/sqrt(area));
       if ((scale.x < (double) *width) || (scale.y < (double) *height))
         {
-          *width=(size_t) (former_width/(distance/sqrt(area))+0.5);
-          *height=(size_t) (former_height/(distance/sqrt(area))+0.5);
+          *width=(unsigned long) (former_width/(distance/sqrt(area)));
+          *height=(unsigned long) (former_height/(distance/sqrt(area)));
         }
       former_width=(*width);
       former_height=(*height);
@@ -1333,7 +1475,7 @@ MagickExport MagickStatusType ParsePageGeometry(const Image *image,
   if (flags == NoValue)
     {
       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
-        "InvalidGeometry","'%s'",geometry);
+        "InvalidGeometry","`%s'",geometry);
       return(flags);
     }
   if ((flags & PercentValue) != 0)
@@ -1343,6 +1485,14 @@ MagickExport MagickStatusType ParsePageGeometry(const Image *image,
     }
   flags=ParseMetaGeometry(geometry,&region_info->x,&region_info->y,
     &region_info->width,&region_info->height);
+  if ((((flags & WidthValue) != 0) || ((flags & HeightValue) != 0)) &&
+      (((flags & PercentValue) != 0) || ((flags & SeparatorValue) == 0)))
+    {
+      if ((flags & WidthValue) == 0)
+        region_info->width=region_info->height;
+      if ((flags & HeightValue) == 0)
+        region_info->height=region_info->width;
+    }
   return(flags);
 }
 \f
@@ -1390,7 +1540,7 @@ MagickExport MagickStatusType ParseRegionGeometry(const Image *image,
     &region_info->width,&region_info->height);
   if (flags == NoValue)
     (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
-      "InvalidGeometry","'%s'",geometry);
+      "InvalidGeometry","`%s'",geometry);
   return(flags);
 }
 \f
@@ -1421,7 +1571,7 @@ MagickExport MagickStatusType ParseRegionGeometry(const Image *image,
 MagickExport void SetGeometry(const Image *image,RectangleInfo *geometry)
 {
   assert(image != (Image *) NULL);
-  assert(image->signature == MagickSignature);
+  assert(image->signature == MagickCoreSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(geometry != (RectangleInfo *) NULL);