2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % GGGG EEEEE OOO M M EEEEE TTTTT RRRR Y Y %
7 % G E O O MM MM E T R R Y Y %
8 % G GG EEE O O M M M EEE T RRRR Y %
9 % G G E O O M M E T R R Y %
10 % GGGG EEEEE OOO M M EEEEE T R R Y %
13 % MagickCore Geometry Methods %
20 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 #include "MagickCore/studio.h"
43 #include "MagickCore/constitute.h"
44 #include "MagickCore/draw.h"
45 #include "MagickCore/exception.h"
46 #include "MagickCore/exception-private.h"
47 #include "MagickCore/geometry.h"
48 #include "MagickCore/memory_.h"
49 #include "MagickCore/string_.h"
50 #include "MagickCore/string-private.h"
51 #include "MagickCore/token.h"
54 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
58 % G e t G e o m e t r y %
62 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
64 % GetGeometry() parses a geometry specification and returns the width,
65 % height, x, and y values. It also returns flags that indicates which
66 % of the four values (width, height, x, y) were located in the string, and
67 % whether the x or y values are negative. In addition, there are flags to
68 % report any meta characters (%, !, <, or >).
70 % The value must form a proper geometry style specification of WxH+X+Y
71 % of integers only, and values can not be separated by comma, colon, or
72 % slash charcaters. See ParseGeometry() below.
74 % Offsets may be prefixed by multiple signs to make offset string
75 % substitutions easier to handle from shell scripts.
76 % For example: "-10-10", "-+10-+10", or "+-10+-10" will generate negtive
77 % offsets, while "+10+10", "++10++10", or "--10--10" will generate positive
80 % The format of the GetGeometry method is:
82 % MagickStatusType GetGeometry(const char *geometry,ssize_t *x,ssize_t *y,
83 % size_t *width,size_t *height)
85 % A description of each parameter follows:
87 % o geometry: The geometry.
89 % o x,y: The x and y offset as determined by the geometry specification.
91 % o width,height: The width and height as determined by the geometry
95 MagickExport MagickStatusType GetGeometry(const char *geometry,ssize_t *x,
96 ssize_t *y,size_t *width,size_t *height)
100 pedantic_geometry[MaxTextExtent],
113 Remove whitespace and meta characters from geometry specification.
116 if ((geometry == (char *) NULL) || (*geometry == '\0'))
118 if (strlen(geometry) >= (MaxTextExtent-1))
120 (void) CopyMagickString(pedantic_geometry,geometry,MaxTextExtent);
121 for (p=pedantic_geometry; *p != '\0'; )
123 if (isspace((int) ((unsigned char) *p)) != 0)
125 (void) CopyMagickString(p,p+1,MaxTextExtent);
134 (void) CopyMagickString(p,p+1,MaxTextExtent);
140 (void) CopyMagickString(p,p+1,MaxTextExtent);
146 (void) CopyMagickString(p,p+1,MaxTextExtent);
152 (void) CopyMagickString(p,p+1,MaxTextExtent);
158 (void) CopyMagickString(p,p+1,MaxTextExtent);
164 (void) CopyMagickString(p,p+1,MaxTextExtent);
170 (void) CopyMagickString(p,p+1,MaxTextExtent);
176 flags|=SeparatorValue;
204 Parse width, height, x, and y.
210 value=StringToDouble(p,&q);
212 if (LocaleNCompare(p,"0x",2) == 0)
213 value=(double) strtol(p,&q,10);
214 if ((*p != '+') && (*p != '-'))
216 c=(int) ((unsigned char) *q);
217 if ((c == 215) || (*q == 'x') || (*q == 'X') || (*q == '\0'))
223 if (LocaleNCompare(p,"0x",2) == 0)
224 *width=(size_t) strtol(p,&p,10);
226 *width=(size_t) floor(StringToDouble(p,&p)+0.5);
231 if ((*p != '+') && (*p != '-'))
233 c=(int) ((unsigned char) *p);
234 if ((c == 215) || (*p == 'x') || (*p == 'X'))
237 if ((*p != '+') && (*p != '-'))
243 *height=(size_t) floor(StringToDouble(p,&p)+0.5);
249 if ((*p == '+') || (*p == '-'))
254 while ((*p == '+') || (*p == '-'))
257 flags^=XNegative; /* negate sign */
261 *x=(ssize_t) ceil(StringToDouble(p,&p)-0.5);
265 if ((flags & XNegative) != 0)
269 if ((*p == '+') || (*p == '-'))
274 while ((*p == '+') || (*p == '-'))
277 flags^=YNegative; /* negate sign */
281 *y=(ssize_t) ceil(StringToDouble(p,&p)-0.5);
285 if ((flags & YNegative) != 0)
289 if ((flags & PercentValue) != 0)
291 if (((flags & SeparatorValue) == 0) && ((flags & HeightValue) == 0))
296 if (((flags & SeparatorValue) != 0) && ((flags & WidthValue) == 0))
300 /* Debugging Geometry */
301 (void) fprintf(stderr,"GetGeometry...\n");
302 (void) fprintf(stderr,"Input: %s\n",geometry);
303 (void) fprintf(stderr,"Flags: %c %c %s %s\n",
304 (flags & WidthValue) ? 'W' : ' ',(flags & HeightValue) ? 'H' : ' ',
305 (flags & XValue) ? ((flags & XNegative) ? "-X" : "+X") : " ",
306 (flags & YValue) ? ((flags & YNegative) ? "-Y" : "+Y") : " ");
307 (void) fprintf(stderr,"Geometry: %ldx%ld%+ld%+ld\n",(long) *width,(long)
308 *height,(long) *x,(long) *y);
314 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
318 % G e t P a g e G e o m e t r y %
322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
324 % GetPageGeometry() replaces any page mneumonic with the equivalent size in
327 % The format of the GetPageGeometry method is:
329 % char *GetPageGeometry(const char *page_geometry)
331 % A description of each parameter follows.
333 % o page_geometry: Specifies a pointer to an array of characters. The
334 % string is either a Postscript page name (e.g. A4) or a postscript page
335 % geometry (e.g. 612x792+36+36).
338 MagickExport char *GetPageGeometry(const char *page_geometry)
343 { "4x6", "288x432" },
344 { "5x7", "360x504" },
345 { "7x9", "504x648" },
346 { "8x10", "576x720" },
347 { "9x11", "648x792" },
348 { "9x12", "648x864" },
349 { "10x13", "720x936" },
350 { "10x14", "720x1008" },
351 { "11x17", "792x1224" },
352 { "a0", "2384x3370" },
353 { "a1", "1684x2384" },
355 { "a2", "1191x1684" },
356 { "a3", "842x1191" },
358 { "a4smaLL", "595x842" },
364 { "archa", "648x864" },
365 { "archb", "864x1296" },
366 { "archC", "1296x1728" },
367 { "archd", "1728x2592" },
368 { "arche", "2592x3456" },
369 { "b0", "2920x4127" },
370 { "b1", "2064x2920" },
372 { "b2", "1460x2064" },
373 { "b3", "1032x1460" },
374 { "b4", "729x1032" },
380 { "c0", "2599x3676" },
381 { "c1", "1837x2599" },
382 { "c2", "1298x1837" },
383 { "c3", "918x1296" },
388 { "executive", "540x720" },
389 { "flsa", "612x936" },
390 { "flse", "612x936" },
391 { "folio", "612x936" },
392 { "halfletter", "396x612" },
393 { "isob0", "2835x4008" },
394 { "isob1", "2004x2835" },
395 { "isob10", "88x125" },
396 { "isob2", "1417x2004" },
397 { "isob3", "1001x1417" },
398 { "isob4", "709x1001" },
399 { "isob5", "499x709" },
400 { "isob6", "354x499" },
401 { "isob7", "249x354" },
402 { "isob8", "176x249" },
403 { "isob9", "125x176" },
404 { "jisb0", "1030x1456" },
405 { "jisb1", "728x1030" },
406 { "jisb2", "515x728" },
407 { "jisb3", "364x515" },
408 { "jisb4", "257x364" },
409 { "jisb5", "182x257" },
410 { "jisb6", "128x182" },
411 { "ledger", "1224x792" },
412 { "legal", "612x1008" },
413 { "letter", "612x792" },
414 { "lettersmaLL", "612x792" },
415 { "quarto", "610x780" },
416 { "statement", "396x612" },
417 { "tabloid", "792x1224" },
418 { (char *) NULL, (char *) NULL }
427 assert(page_geometry != (char *) NULL);
428 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",page_geometry);
429 page=AcquireString(page_geometry);
430 for (i=0; *PageSizes[i] != (char *) NULL; i++)
431 if (LocaleNCompare(PageSizes[i][0],page,strlen(PageSizes[i][0])) == 0)
440 Replace mneumonic with the equivalent size in dots-per-inch.
442 (void) CopyMagickString(page,PageSizes[i][1],MaxTextExtent);
443 (void) ConcatenateMagickString(page,page_geometry+
444 strlen(PageSizes[i][0]),MaxTextExtent);
445 flags=GetGeometry(page,&geometry.x,&geometry.y,&geometry.width,
447 if ((flags & GreaterValue) == 0)
448 (void) ConcatenateMagickString(page,">",MaxTextExtent);
455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
459 % G r a v i t y A d j u s t G e o m e t r y %
462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
464 % GravityAdjustGeometry() adjusts the offset of a region with regard to the
465 % given: width, height and gravity; against which it is positioned.
467 % The region should also have an appropriate width and height to correctly
468 % set the right offset of the top left corner of the region.
470 % The format of the GravityAdjustGeometry method is:
472 % void GravityAdjustGeometry(const size_t width, const size_t height,
473 % const GravityType gravity,RectangleInfo *region);
475 % A description of each parameter follows:
477 % o width, height: the larger area the region is relative to
479 % o gravity: the edge/corner the current offset is relative to
481 % o region: The region requiring a offset adjustment relative to gravity
484 MagickExport void GravityAdjustGeometry(const size_t width,
485 const size_t height,const GravityType gravity,RectangleInfo *region)
487 if (region->height == 0)
488 region->height=height;
489 if (region->width == 0)
493 case NorthEastGravity:
495 case SouthEastGravity:
497 region->x=(ssize_t) (width-region->width-region->x);
504 region->x+=(ssize_t) (width/2-region->width/2);
508 case NorthWestGravity:
510 case SouthWestGravity:
516 case SouthWestGravity:
518 case SouthEastGravity:
520 region->y=(ssize_t) (height-region->height-region->y);
527 region->y+=(ssize_t) (height/2-region->height/2);
531 case NorthWestGravity:
533 case NorthEastGravity:
541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
545 + I s G e o m e t r y %
549 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
551 % IsGeometry() returns MagickTrue if the geometry specification is valid.
552 % Examples are 100, 100x200, x200, 100x200+10+20, +10+20, 200%, 200x200!, etc.
554 % The format of the IsGeometry method is:
556 % MagickBooleanType IsGeometry(const char *geometry)
558 % A description of each parameter follows:
560 % o geometry: This string is the geometry specification.
563 MagickExport MagickBooleanType IsGeometry(const char *geometry)
571 if (geometry == (const char *) NULL)
573 flags=ParseGeometry(geometry,&geometry_info);
574 return(flags != NoValue ? MagickTrue : MagickFalse);
578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
582 + I s S c e n e G e o m e t r y %
586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
588 % IsSceneGeometry() returns MagickTrue if the geometry is a valid scene
589 % specification (e.g. [1], [1-9], [1,7,4]).
591 % The format of the IsSceneGeometry method is:
593 % MagickBooleanType IsSceneGeometry(const char *geometry,
594 % const MagickBooleanType pedantic)
596 % A description of each parameter follows:
598 % o geometry: This string is the geometry specification.
600 % o pedantic: A value other than 0 invokes a more restrictive set of
601 % conditions for a valid specification (e.g. [1], [1-4], [4-1]).
604 MagickExport MagickBooleanType IsSceneGeometry(const char *geometry,
605 const MagickBooleanType pedantic)
613 if (geometry == (const char *) NULL)
616 value=StringToDouble(geometry,&p);
620 if (strspn(geometry,"0123456789-, ") != strlen(geometry))
622 if ((pedantic != MagickFalse) && (strchr(geometry,',') != (char *) NULL))
628 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
632 % P a r s e A b s o l u t e G e o m e t r y %
636 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
638 % ParseAbsoluteGeometry() returns a region as defined by the geometry string,
639 % without any modification by percentages or gravity.
641 % It currently just a wrapper around GetGeometry(), but may be expanded in
642 % the future to handle other positioning information.
644 % The format of the ParseAbsoluteGeometry method is:
646 % MagickStatusType ParseAbsoluteGeometry(const char *geometry,
647 % RectangleInfo *region_info)
649 % A description of each parameter follows:
651 % o geometry: The geometry string (e.g. "100x100+10+10").
653 % o region_info: the region as defined by the geometry string.
656 MagickExport MagickStatusType ParseAbsoluteGeometry(const char *geometry,
657 RectangleInfo *region_info)
662 flags=GetGeometry(geometry,®ion_info->x,®ion_info->y,
663 ®ion_info->width,®ion_info->height);
668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
672 % P a r s e A f f i n e G e o m e t r y %
676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
678 % ParseAffineGeometry() returns an affine matrix as defined by a string of 4
679 % to 6 comma/space separated floating point values.
681 % The affine matrix determinant is checked for validity of the values.
683 % The format of the ParseAffineGeometry method is:
685 % MagickStatusType ParseAffineGeometry(const char *geometry,
686 % AffineMatrix *affine_matrix,ExceptionInfo *exception)
688 % A description of each parameter follows:
690 % o geometry: The geometry string (e.g. "1.0,0.0,0.0,1.0,3.2,1.2").
692 % o affine_matrix: the affine matrix as defined by the geometry string.
694 % o exception: return any errors or warnings in this structure.
697 MagickExport MagickStatusType ParseAffineGeometry(const char *geometry,
698 AffineMatrix *affine_matrix,ExceptionInfo *exception)
701 token[MaxTextExtent];
715 GetAffineMatrix(affine_matrix);
718 for (i=0; (*p != '\0') && (i < 6); i++)
720 GetMagickToken(p,&p,token);
722 GetMagickToken(p,&p,token);
727 affine_matrix->sx=StringToDouble(token,(char **) NULL);
732 affine_matrix->rx=StringToDouble(token,(char **) NULL);
737 affine_matrix->ry=StringToDouble(token,(char **) NULL);
742 affine_matrix->sy=StringToDouble(token,(char **) NULL);
747 affine_matrix->tx=StringToDouble(token,(char **) NULL);
753 affine_matrix->ty=StringToDouble(token,(char **) NULL);
759 determinant=(affine_matrix->sx*affine_matrix->sy-affine_matrix->rx*
761 if (fabs(determinant) < MagickEpsilon)
762 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
763 "InvalidArgument","'%s' : 'Indeterminate Matrix'",geometry);
768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
772 % P a r s e G e o m e t r y %
776 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
778 % ParseGeometry() parses a geometry specification and returns the sigma,
779 % rho, xi, and psi values. It also returns flags that indicates which
780 % of the four values (sigma, rho, xi, psi) were located in the string, and
781 % whether the xi or pi values are negative.
783 % In addition, it reports if there are any of meta characters (%, !, <, >, @,
784 % and ^) flags present. It does not report the location of the percentage
785 % relative to the values.
787 % Values may also be seperated by commas, colons, or slashes, and offsets.
788 % Offsets may be prefixed by multiple signs to make offset string
789 % substitutions easier to handle from shell scripts.
790 % For example: "-10-10", "-+10-+10", or "+-10+-10" will generate negtive
791 % offsets, while "+10+10", "++10++10", or "--10--10" will generate positive
794 % The format of the ParseGeometry method is:
796 % MagickStatusType ParseGeometry(const char *geometry,
797 % GeometryInfo *geometry_info)
799 % A description of each parameter follows:
801 % o geometry: The geometry string (e.g. "100x100+10+10").
803 % o geometry_info: returns the parsed width/height/x/y in this structure.
806 MagickExport MagickStatusType ParseGeometry(const char *geometry,
807 GeometryInfo *geometry_info)
811 pedantic_geometry[MaxTextExtent],
824 Remove whitespaces meta characters from geometry specification.
826 assert(geometry_info != (GeometryInfo *) NULL);
828 if ((geometry == (char *) NULL) || (*geometry == '\0'))
830 if (strlen(geometry) >= (MaxTextExtent-1))
832 (void) CopyMagickString(pedantic_geometry,geometry,MaxTextExtent);
833 for (p=pedantic_geometry; *p != '\0'; )
835 if (isspace((int) ((unsigned char) *p)) != 0)
837 (void) CopyMagickString(p,p+1,MaxTextExtent);
840 c=(int) ((unsigned char) *p);
846 (void) CopyMagickString(p,p+1,MaxTextExtent);
852 (void) CopyMagickString(p,p+1,MaxTextExtent);
858 (void) CopyMagickString(p,p+1,MaxTextExtent);
864 (void) CopyMagickString(p,p+1,MaxTextExtent);
870 (void) CopyMagickString(p,p+1,MaxTextExtent);
876 (void) CopyMagickString(p,p+1,MaxTextExtent);
882 (void) CopyMagickString(p,p+1,MaxTextExtent);
888 flags|=SeparatorValue;
923 Parse rho, sigma, xi, psi, and optionally chi.
929 value=StringToDouble(p,&q);
930 if (LocaleNCompare(p,"0x",2) == 0)
931 value=(double) strtol(p,&q,10);
932 c=(int) ((unsigned char) *q);
933 if ((c == 215) || (*q == 'x') || (*q == 'X') || (*q == ',') ||
934 (*q == '/') || (*q == ':') || (*q =='\0'))
940 if (LocaleNCompare(p,"0x",2) == 0)
941 value=(double) strtol(p,&p,10);
943 value=StringToDouble(p,&p);
947 geometry_info->rho=value;
951 c=(int) ((unsigned char) *p);
952 if ((c == 215) || (*p == 'x') || (*p == 'X') || (*p == ',') || (*p == '/') ||
959 while (isspace((int) ((unsigned char) *p)) != 0)
961 c=(int) ((unsigned char) *q);
962 if (((c != 215) && (*q != 'x') && (*q != 'X')) || ((*p != '+') &&
966 value=StringToDouble(p,&p);
970 geometry_info->sigma=value;
974 while (isspace((int) ((unsigned char) *p)) != 0)
976 if ((*p == '+') || (*p == '-') || (*p == ',') || (*p == '/') || (*p == ':'))
981 if ((*p == ',') || (*p == '/') || (*p == ':') )
983 while ((*p == '+') || (*p == '-'))
986 flags^=XiNegative; /* negate sign */
990 value=StringToDouble(p,&p);
994 if ((flags & XiNegative) != 0)
996 geometry_info->xi=value;
998 while (isspace((int) ((unsigned char) *p)) != 0)
1000 if ((*p == '+') || (*p == '-') || (*p == ',') || (*p == '/') ||
1006 if ((*p == ',') || (*p == '/') || (*p == ':'))
1008 while ((*p == '+') || (*p == '-'))
1011 flags^=PsiNegative; /* negate sign */
1015 value=StringToDouble(p,&p);
1019 if ((flags & PsiNegative) != 0)
1021 geometry_info->psi=value;
1024 while (isspace((int) ((unsigned char) *p)) != 0)
1026 if ((*p == '+') || (*p == '-') || (*p == ',') || (*p == '/') ||
1032 if ((*p == ',') || (*p == '/') || (*p == ':'))
1034 while ((*p == '+') || (*p == '-'))
1037 flags^=ChiNegative; /* negate sign */
1041 value=StringToDouble(p,&p);
1045 if ((flags & ChiNegative) != 0)
1047 geometry_info->chi=value;
1051 if (strchr(pedantic_geometry,':') != (char *) NULL)
1054 Normalize sampling factor (e.g. 4:2:2 => 2x1).
1056 geometry_info->rho/=geometry_info->sigma;
1057 geometry_info->sigma=1.0;
1058 if (geometry_info->xi == 0.0)
1059 geometry_info->sigma=2.0;
1061 if (((flags & SigmaValue) == 0) && ((flags & XiValue) != 0) &&
1062 ((flags & PsiValue) == 0))
1065 Support negative height values (e.g. 30x-20).
1067 geometry_info->sigma=geometry_info->xi;
1068 geometry_info->xi=0.0;
1072 if ((flags & PercentValue) != 0)
1074 if (((flags & SeparatorValue) == 0) && ((flags & SigmaValue) == 0))
1075 geometry_info->sigma=geometry_info->rho;
1076 if (((flags & SeparatorValue) != 0) && ((flags & RhoValue) == 0))
1077 geometry_info->rho=geometry_info->sigma;
1080 /* Debugging Geometry */
1081 (void) fprintf(stderr,"ParseGeometry...\n");
1082 (void) fprintf(stderr,"Flags: %c %c %s %s %s\n",
1083 (flags & RhoValue) ? 'W' : ' ',(flags & SigmaValue) ? 'H' : ' ',
1084 (flags & XiValue) ? ((flags & XiNegative) ? "-X" : "+X") : " ",
1085 (flags & PsiValue) ? ((flags & PsiNegative) ? "-Y" : "+Y") : " ",
1086 (flags & ChiValue) ? ((flags & ChiNegative) ? "-Z" : "+Z") : " ");
1087 (void) fprintf(stderr,"Geometry: %lg,%lg,%lg,%lg,%lg\n",geometry_info->rho,
1088 geometry_info->sigma,geometry_info->xi,geometry_info->psi,
1089 geometry_info->chi);
1095 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1099 % P a r s e G r a v i t y G e o m e t r y %
1103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1105 % ParseGravityGeometry() returns a region as defined by the geometry string
1106 % with respect to the given image page (canvas) dimensions and the images
1109 % This is typically used for specifing a area within a given image for
1110 % cropping images to a smaller size, chopping out rows and or columns, or
1111 % resizing and positioning overlay images.
1113 % Percentages are relative to image size and not page size, and are set to
1114 % nearest integer (pixel) size.
1116 % The format of the ParseGravityGeometry method is:
1118 % MagickStatusType ParseGravityGeometry(Image *image,const char *geometry,
1119 % RectangeInfo *region_info,ExceptionInfo *exception)
1121 % A description of each parameter follows:
1123 % o geometry: The geometry string (e.g. "100x100+10+10").
1125 % o region_info: the region as defined by the geometry string with respect
1126 % to the image dimensions and its gravity.
1128 % o exception: return any errors or warnings in this structure.
1131 MagickExport MagickStatusType ParseGravityGeometry(const Image *image,
1132 const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
1141 SetGeometry(image,region_info);
1142 if (image->page.width != 0)
1143 region_info->width=image->page.width;
1144 if (image->page.height != 0)
1145 region_info->height=image->page.height;
1146 flags=ParseAbsoluteGeometry(geometry,region_info);
1147 if (flags == NoValue)
1149 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1150 "InvalidGeometry","'%s'",geometry);
1153 if ((flags & PercentValue) != 0)
1165 Geometry is a percentage of the image size, not canvas size
1167 if (image->gravity != UndefinedGravity)
1168 flags|=XValue | YValue;
1169 status=ParseGeometry(geometry,&geometry_info);
1170 scale.x=geometry_info.rho;
1171 if ((status & RhoValue) == 0)
1173 scale.y=geometry_info.sigma;
1174 if ((status & SigmaValue) == 0)
1176 region_info->width=(size_t) floor((scale.x*image->columns/100.0)+0.5);
1177 region_info->height=(size_t) floor((scale.y*image->rows/100.0)+0.5);
1180 Adjust offset according to gravity setting.
1182 width=region_info->width;
1183 height=region_info->height;
1185 region_info->width=image->page.width | image->columns;
1187 region_info->height=image->page.height | image->rows;
1188 GravityAdjustGeometry(image->columns,image->rows,image->gravity,region_info);
1189 region_info->width=width;
1190 region_info->height=height;
1195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1199 + P a r s e M e t a G e o m e t r y %
1203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1205 % ParseMetaGeometry() is similar to GetGeometry() except the returned
1206 % geometry is modified as determined by the meta characters: %, !, <, >, @,
1207 % and ^ in relation to image resizing.
1209 % Final image dimensions are adjusted so as to preserve the aspect ratio as
1210 % much as possible, while generating a integer (pixel) size, and fitting the
1211 % image within the specified geometry width and height.
1213 % Flags are interpreted...
1214 % % geometry size is given percentage of original width and height given
1215 % ! do not try to preserve aspect ratio
1216 % < only enlarge images smaller that geometry
1217 % > only shrink images larger than geometry
1218 % @ Fit image to contain at most this many pixels
1219 % ^ Contain the given geometry given, (minimal dimensions given)
1221 % The format of the ParseMetaGeometry method is:
1223 % MagickStatusType ParseMetaGeometry(const char *geometry,ssize_t *x,
1224 % ssize_t *y, size_t *width,size_t *height)
1226 % A description of each parameter follows:
1228 % o geometry: The geometry string (e.g. "100x100+10+10").
1230 % o x,y: The x and y offset, set according to the geometry specification.
1232 % o width,height: The width and height of original image, modified by
1233 % the given geometry specification.
1237 static inline size_t MagickMax(const size_t x,
1245 MagickExport MagickStatusType ParseMetaGeometry(const char *geometry,ssize_t *x,
1246 ssize_t *y,size_t *width,size_t *height)
1259 Ensure the image geometry is valid.
1261 assert(x != (ssize_t *) NULL);
1262 assert(y != (ssize_t *) NULL);
1263 assert(width != (size_t *) NULL);
1264 assert(height != (size_t *) NULL);
1265 if ((geometry == (char *) NULL) || (*geometry == '\0'))
1267 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",geometry);
1269 Parse geometry using GetGeometry.
1271 SetGeometryInfo(&geometry_info);
1272 former_width=(*width);
1273 former_height=(*height);
1274 flags=GetGeometry(geometry,x,y,width,height);
1275 if ((flags & PercentValue) != 0)
1284 Geometry is a percentage of the image size.
1286 flags=ParseGeometry(geometry,&geometry_info);
1287 scale.x=geometry_info.rho;
1288 if ((flags & RhoValue) == 0)
1290 scale.y=geometry_info.sigma;
1291 if ((flags & SigmaValue) == 0)
1293 *width=(size_t) floor(scale.x*former_width/100.0+0.5);
1294 *height=(size_t) floor(scale.y*former_height/100.0+0.5);
1295 former_width=(*width);
1296 former_height=(*height);
1298 if (((flags & AspectValue) != 0) || ((*width == former_width) &&
1299 (*height == former_height)))
1301 if ((flags & RhoValue) == 0)
1302 *width=former_width;
1303 if ((flags & SigmaValue) == 0)
1304 *height=former_height;
1312 Respect aspect ratio of the image.
1314 if ((former_width == 0) || (former_height == 0))
1317 if (((flags & RhoValue) != 0) && (flags & SigmaValue) != 0)
1319 scale_factor=(double) *width/(double) former_width;
1320 if ((flags & MinimumValue) == 0)
1322 if (scale_factor > ((double) *height/(double) former_height))
1323 scale_factor=(double) *height/(double) former_height;
1326 if (scale_factor < ((double) *height/(double) former_height))
1327 scale_factor=(double) *height/(double) former_height;
1330 if ((flags & RhoValue) != 0)
1332 scale_factor=(double) *width/(double) former_width;
1333 if (((flags & MinimumValue) != 0) &&
1334 (scale_factor < ((double) *width/(double) former_height)))
1335 scale_factor=(double) *width/(double) former_height;
1339 scale_factor=(double) *height/(double) former_height;
1340 if (((flags & MinimumValue) != 0) &&
1341 (scale_factor < ((double) *height/(double) former_width)))
1342 scale_factor=(double) *height/(double) former_width;
1344 *width=MagickMax((size_t) floor(scale_factor*former_width+0.5),1UL);
1345 *height=MagickMax((size_t) floor(scale_factor*former_height+0.5),1UL);
1347 if ((flags & GreaterValue) != 0)
1349 if (former_width < *width)
1350 *width=former_width;
1351 if (former_height < *height)
1352 *height=former_height;
1354 if ((flags & LessValue) != 0)
1356 if (former_width > *width)
1357 *width=former_width;
1358 if (former_height > *height)
1359 *height=former_height;
1361 if ((flags & AreaValue) != 0)
1371 Geometry is a maximum area in pixels.
1373 (void) ParseGeometry(geometry,&geometry_info);
1374 area=geometry_info.rho;
1375 distance=sqrt((double) former_width*former_height);
1376 scale.x=(double) former_width/(distance/sqrt((double) area));
1377 scale.y=(double) former_height/(distance/sqrt((double) area));
1378 if ((scale.x < (double) *width) || (scale.y < (double) *height))
1380 *width=(size_t) (former_width/(distance/sqrt(area))+0.5);
1381 *height=(size_t) (former_height/(distance/sqrt(area))+0.5);
1383 former_width=(*width);
1384 former_height=(*height);
1390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1394 % P a r s e P a g e G e o m e t r y %
1398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1400 % ParsePageGeometry() returns a region as defined by the geometry string with
1401 % respect to the image page (canvas) dimensions.
1403 % WARNING: Percentage dimensions remain relative to the actual image
1404 % dimensions, and not canvas dimensions.
1406 % The format of the ParsePageGeometry method is:
1408 % MagickStatusType ParsePageGeometry(const Image *image,
1409 % const char *geometry,RectangeInfo *region_info,
1410 % ExceptionInfo *exception)
1412 % A description of each parameter follows:
1414 % o geometry: The geometry string (e.g. "100x100+10+10").
1416 % o region_info: the region as defined by the geometry string with
1417 % respect to the image and its gravity.
1419 % o exception: return any errors or warnings in this structure.
1422 MagickExport MagickStatusType ParsePageGeometry(const Image *image,
1423 const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
1428 SetGeometry(image,region_info);
1429 if (image->page.width != 0)
1430 region_info->width=image->page.width;
1431 if (image->page.height != 0)
1432 region_info->height=image->page.height;
1433 flags=ParseAbsoluteGeometry(geometry,region_info);
1434 if (flags == NoValue)
1436 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1437 "InvalidGeometry","'%s'",geometry);
1440 if ((flags & PercentValue) != 0)
1442 region_info->width=image->columns;
1443 region_info->height=image->rows;
1445 flags=ParseMetaGeometry(geometry,®ion_info->x,®ion_info->y,
1446 ®ion_info->width,®ion_info->height);
1447 if ((((flags & WidthValue) != 0) || ((flags & HeightValue) != 0)) &&
1448 (((flags & PercentValue) != 0) || ((flags & SeparatorValue) == 0)))
1450 if ((flags & WidthValue) == 0)
1451 region_info->width=region_info->height;
1452 if ((flags & HeightValue) == 0)
1453 region_info->height=region_info->width;
1459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1463 % P a r s e R e g i o n G e o m e t r y %
1467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1469 % ParseRegionGeometry() returns a region as defined by the geometry string
1470 % with respect to the image dimensions and aspect ratio.
1472 % This is basically a wrapper around ParseMetaGeometry. This is typically
1473 % used to parse a geometry string to work out the final integer dimensions
1474 % for image resizing.
1476 % The format of the ParseRegionGeometry method is:
1478 % MagickStatusType ParseRegionGeometry(const Image *image,
1479 % const char *geometry,RectangeInfo *region_info,
1480 % ExceptionInfo *exception)
1482 % A description of each parameter follows:
1484 % o geometry: The geometry string (e.g. "100x100+10+10").
1486 % o region_info: the region as defined by the geometry string.
1488 % o exception: return any errors or warnings in this structure.
1491 MagickExport MagickStatusType ParseRegionGeometry(const Image *image,
1492 const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
1497 SetGeometry(image,region_info);
1498 flags=ParseMetaGeometry(geometry,®ion_info->x,®ion_info->y,
1499 ®ion_info->width,®ion_info->height);
1500 if (flags == NoValue)
1501 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1502 "InvalidGeometry","'%s'",geometry);
1507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1511 % S e t G e o m e t r y %
1515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1517 % SetGeometry() sets the geometry to its default values.
1519 % The format of the SetGeometry method is:
1521 % SetGeometry(const Image *image,RectangleInfo *geometry)
1523 % A description of each parameter follows:
1525 % o image: the image.
1527 % o geometry: the geometry.
1530 MagickExport void SetGeometry(const Image *image,RectangleInfo *geometry)
1532 assert(image != (Image *) NULL);
1533 assert(image->signature == MagickSignature);
1534 if (image->debug != MagickFalse)
1535 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1536 assert(geometry != (RectangleInfo *) NULL);
1537 (void) ResetMagickMemory(geometry,0,sizeof(*geometry));
1538 geometry->width=image->columns;
1539 geometry->height=image->rows;
1543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1547 % S e t G e o m e t r y I n f o %
1551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1553 % SetGeometryInfo sets the GeometryInfo structure to its default values.
1555 % The format of the SetGeometryInfo method is:
1557 % SetGeometryInfo(GeometryInfo *geometry_info)
1559 % A description of each parameter follows:
1561 % o geometry_info: the geometry info structure.
1564 MagickExport void SetGeometryInfo(GeometryInfo *geometry_info)
1566 assert(geometry_info != (GeometryInfo *) NULL);
1567 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1568 (void) ResetMagickMemory(geometry_info,0,sizeof(*geometry_info));