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-2010 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 "magick/studio.h"
43 #include "magick/constitute.h"
44 #include "magick/draw.h"
45 #include "magick/exception.h"
46 #include "magick/exception-private.h"
47 #include "magick/geometry.h"
48 #include "magick/memory_.h"
49 #include "magick/string_.h"
50 #include "magick/string-private.h"
51 #include "magick/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 format of the GetGeometry method is:
72 % MagickStatusType GetGeometry(const char *geometry,ssize_t *x,ssize_t *y,
73 % size_t *width,size_t *height)
75 % A description of each parameter follows:
77 % o geometry: The geometry.
79 % o x,y: The x and y offset as determined by the geometry specification.
81 % o width,height: The width and height as determined by the geometry
85 MagickExport MagickStatusType GetGeometry(const char *geometry,ssize_t *x,ssize_t *y,
86 size_t *width,size_t *height)
90 pedantic_geometry[MaxTextExtent],
100 Remove whitespace and meta characters from geometry specification.
103 if ((geometry == (char *) NULL) || (*geometry == '\0'))
105 if (strlen(geometry) >= MaxTextExtent)
107 (void) CopyMagickString(pedantic_geometry,geometry,MaxTextExtent);
108 for (p=pedantic_geometry; *p != '\0'; )
110 if (isspace((int) ((unsigned char) *p)) != 0)
112 (void) CopyMagickString(p,p+1,MaxTextExtent);
120 (void) CopyMagickString(p,p+1,MaxTextExtent);
126 (void) CopyMagickString(p,p+1,MaxTextExtent);
132 (void) CopyMagickString(p,p+1,MaxTextExtent);
138 (void) CopyMagickString(p,p+1,MaxTextExtent);
144 (void) CopyMagickString(p,p+1,MaxTextExtent);
150 (void) CopyMagickString(p,p+1,MaxTextExtent);
156 (void) CopyMagickString(p,p+1,MaxTextExtent);
185 Parse width, height, x, and y.
192 if (LocaleNCompare(p,"0x",2) == 0)
193 value=(double) strtol(p,&q,10);
194 if ((((int) *q) == -41) || (*q == 'x') || (*q == 'X') || (*q == '\0'))
200 if (LocaleNCompare(p,"0x",2) == 0)
201 *width=(size_t) strtol(p,&p,10);
203 *width=(size_t) floor(strtod(p,&p)+0.5);
207 if ((((int) *p) == -41) || (*p == 'x') || (*p == 'X'))
210 if ((*p != '+') && (*p != '-'))
216 *height=(size_t) floor(strtod(p,&p)+0.5);
221 if ((*p == '+') || (*p == '-'))
229 *x=(ssize_t) ceil(strtod(p,&p)-0.5);
232 if ((*p == '+') || (*p == '-'))
240 *y=(ssize_t) ceil(strtod(p,&p)-0.5);
249 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
253 % G e t P a g e G e o m e t r y %
257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
259 % GetPageGeometry() replaces any page mneumonic with the equivalent size in
262 % The format of the GetPageGeometry method is:
264 % char *GetPageGeometry(const char *page_geometry)
266 % A description of each parameter follows.
268 % o page_geometry: Specifies a pointer to an array of characters.
269 % The string is either a Postscript page name (e.g. A4) or a postscript
270 % page geometry (e.g. 612x792+36+36).
273 MagickExport char *GetPageGeometry(const char *page_geometry)
278 { "4x6", "288x432" },
279 { "5x7", "360x504" },
280 { "7x9", "504x648" },
281 { "8x10", "576x720" },
282 { "9x11", "648x792" },
283 { "9x12", "648x864" },
284 { "10x13", "720x936" },
285 { "10x14", "720x1008" },
286 { "11x17", "792x1224" },
287 { "a0", "2384x3370" },
288 { "a1", "1684x2384" },
290 { "a2", "1191x1684" },
291 { "a3", "842x1191" },
293 { "a4smaLL", "595x842" },
299 { "archa", "648x864" },
300 { "archb", "864x1296" },
301 { "archC", "1296x1728" },
302 { "archd", "1728x2592" },
303 { "arche", "2592x3456" },
304 { "b0", "2920x4127" },
305 { "b1", "2064x2920" },
307 { "b2", "1460x2064" },
308 { "b3", "1032x1460" },
309 { "b4", "729x1032" },
315 { "c0", "2599x3676" },
316 { "c1", "1837x2599" },
317 { "c2", "1298x1837" },
318 { "c3", "918x1296" },
323 { "executive", "540x720" },
324 { "flsa", "612x936" },
325 { "flse", "612x936" },
326 { "folio", "612x936" },
327 { "halfletter", "396x612" },
328 { "isob0", "2835x4008" },
329 { "isob1", "2004x2835" },
330 { "isob10", "88x125" },
331 { "isob2", "1417x2004" },
332 { "isob3", "1001x1417" },
333 { "isob4", "709x1001" },
334 { "isob5", "499x709" },
335 { "isob6", "354x499" },
336 { "isob7", "249x354" },
337 { "isob8", "176x249" },
338 { "isob9", "125x176" },
339 { "jisb0", "1030x1456" },
340 { "jisb1", "728x1030" },
341 { "jisb2", "515x728" },
342 { "jisb3", "364x515" },
343 { "jisb4", "257x364" },
344 { "jisb5", "182x257" },
345 { "jisb6", "128x182" },
346 { "ledger", "1224x792" },
347 { "legal", "612x1008" },
348 { "letter", "612x792" },
349 { "lettersmaLL", "612x792" },
350 { "quarto", "610x780" },
351 { "statement", "396x612" },
352 { "tabloid", "792x1224" },
353 { (char *) NULL, (char *) NULL }
362 assert(page_geometry != (char *) NULL);
363 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",page_geometry);
364 page=AcquireString(page_geometry);
365 for (i=0; *PageSizes[i] != (char *) NULL; i++)
366 if (LocaleNCompare(PageSizes[i][0],page,strlen(PageSizes[i][0])) == 0)
375 Replace mneumonic with the equivalent size in dots-per-inch.
377 (void) CopyMagickString(page,PageSizes[i][1],MaxTextExtent);
378 (void) ConcatenateMagickString(page,page_geometry+
379 strlen(PageSizes[i][0]),MaxTextExtent);
380 flags=GetGeometry(page,&geometry.x,&geometry.y,&geometry.width,
382 if ((flags & GreaterValue) == 0)
383 (void) ConcatenateMagickString(page,">",MaxTextExtent);
390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
394 % G r a v i t y A d j u s t G e o m e t r y %
398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
400 % GravityAdjustGeometry() adjusts the offset of a region with regard to the
401 % given: width, height and gravity; against which it is positioned.
403 % The region should also have an appropriate width and height to correctly
404 % set the right offset of the top left corner of the region.
406 % The format of the GravityAdjustGeometry method is:
408 % void GravityAdjustGeometry(const size_t width,
409 % const size_t height,const GravityType gravity,
410 % RectangleInfo *region);
412 % A description of each parameter follows:
414 % o width, height: the larger area the region is relative to
416 % o gravity: the edge/corner the current offset is relative to
418 % o region: The region requiring a offset adjustment relative to gravity
421 MagickExport void GravityAdjustGeometry(const size_t width,
422 const size_t height,const GravityType gravity,RectangleInfo *region)
424 if (region->height == 0)
425 region->height=height;
426 if (region->width == 0)
430 case NorthEastGravity:
432 case SouthEastGravity:
434 region->x=(ssize_t) (width-region->width-region->x);
442 region->x+=(ssize_t) (width/2-region->width/2);
446 case NorthWestGravity:
448 case SouthWestGravity:
454 case SouthWestGravity:
456 case SouthEastGravity:
458 region->y=(ssize_t) (height-region->height-region->y);
466 region->y+=(ssize_t) (height/2-region->height/2);
470 case NorthWestGravity:
472 case NorthEastGravity:
480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484 + I s G e o m e t r y %
488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490 % IsGeometry() returns MagickTrue if the geometry specification is valid.
491 % Examples are 100, 100x200, x200, 100x200+10+20, +10+20, 200%, 200x200!, etc.
493 % The format of the IsGeometry method is:
495 % MagickBooleanType IsGeometry(const char *geometry)
497 % A description of each parameter follows:
499 % o geometry: This string is the geometry specification.
502 MagickExport MagickBooleanType IsGeometry(const char *geometry)
510 if (geometry == (const char *) NULL)
512 flags=ParseGeometry(geometry,&geometry_info);
513 if (flags == NoValue)
514 flags=ParseGeometry(geometry+1,&geometry_info); /* i.e. +-4+-4 */
515 return(flags != NoValue ? MagickTrue : MagickFalse);
519 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
523 + I s S c e n e G e o m e t r y %
527 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
529 % IsSceneGeometry() returns MagickTrue if the geometry is a valid scene
530 % specification (e.g. [1], [1-9], [1,7,4]).
532 % The format of the IsSceneGeometry method is:
534 % MagickBooleanType IsSceneGeometry(const char *geometry,
535 % const MagickBooleanType pedantic)
537 % A description of each parameter follows:
539 % o geometry: This string is the geometry specification.
541 % o pedantic: A value other than 0 invokes a more restrictive set of
542 % conditions for a valid specification (e.g. [1], [1-4], [4-1]).
545 MagickExport MagickBooleanType IsSceneGeometry(const char *geometry,
546 const MagickBooleanType pedantic)
554 if (geometry == (const char *) NULL)
557 value=strtod(geometry,&p);
560 if (strspn(geometry,"0123456789-, ") != strlen(geometry))
562 if ((pedantic != MagickFalse) && (strchr(geometry,',') != (char *) NULL))
568 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
572 % P a r s e A b s o l u t e G e o m e t r y %
576 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
578 % ParseAbsoluteGeometry() returns a region as defined by the geometry string.
580 % The format of the ParseAbsoluteGeometry method is:
582 % MagickStatusType ParseAbsoluteGeometry(const char *geometry,
583 % RectangleInfo *region_info)
585 % A description of each parameter follows:
587 % o geometry: The geometry (e.g. 100x100+10+10).
589 % o region_info: the region as defined by the geometry string.
592 MagickExport MagickStatusType ParseAbsoluteGeometry(const char *geometry,
593 RectangleInfo *region_info)
598 flags=GetGeometry(geometry,®ion_info->x,®ion_info->y,
599 ®ion_info->width,®ion_info->height);
604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
608 % P a r s e A f f i n e G e o m e t r y %
612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
614 % ParseAffineGeometry() returns an affine matrix as defined by the geometry
617 % The format of the ParseAffineGeometry method is:
619 % MagickStatusType ParseAffineGeometry(const char *geometry,
620 % AffineMatrix *affine_matrix,ExceptionInfo *exception)
622 % A description of each parameter follows:
624 % o geometry: The geometry (e.g. 1.0,0.0,0.0,1.0,3.2,1.2).
626 % o affine_matrix: the affine matrix as defined by the geometry string.
628 % o exception: return any errors or warnings in this structure.
631 MagickExport MagickStatusType ParseAffineGeometry(const char *geometry,
632 AffineMatrix *affine_matrix,ExceptionInfo *exception)
635 token[MaxTextExtent];
649 GetAffineMatrix(affine_matrix);
652 for (i=0; (*p != '\0') && (i < 6); i++)
654 GetMagickToken(p,&p,token);
656 GetMagickToken(p,&p,token);
659 case 0: affine_matrix->sx=StringToDouble(token); break;
660 case 1: affine_matrix->rx=StringToDouble(token); break;
661 case 2: affine_matrix->ry=StringToDouble(token); break;
662 case 3: affine_matrix->sy=StringToDouble(token); break;
663 case 4: affine_matrix->tx=StringToDouble(token); flags|=XValue; break;
664 case 5: affine_matrix->ty=StringToDouble(token); flags|=YValue; break;
667 determinant=(affine_matrix->sx*affine_matrix->sy-affine_matrix->rx*
669 if (fabs(determinant) < MagickEpsilon)
670 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
671 "InvalidGeometry","`%s'",geometry);
676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
680 % P a r s e G e o m e t r y %
684 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
686 % ParseGeometry() parses a geometry specification and returns the sigma,
687 % rho, xi, and psi values. It also returns flags that indicates which
688 % of the four values (sigma, rho, xi, psi) were located in the string, and
689 % whether the xi or pi values are negative. In addition, there are flags to
690 % report any meta characters (%, !, <, or >).
692 % The format of the ParseGeometry method is:
694 % MagickStatusType ParseGeometry(const char *geometry,
695 % GeometryInfo *geometry_info)
697 % A description of each parameter follows:
699 % o geometry: The geometry.
701 % o geometry_info: returns the parsed width/height/x/y in this structure.
704 MagickExport MagickStatusType ParseGeometry(const char *geometry,
705 GeometryInfo *geometry_info)
709 pedantic_geometry[MaxTextExtent],
719 Remove whitespaces meta characters from geometry specification.
721 assert(geometry_info != (GeometryInfo *) NULL);
723 if ((geometry == (char *) NULL) || (*geometry == '\0'))
725 if (strlen(geometry) >= MaxTextExtent)
727 (void) CopyMagickString(pedantic_geometry,geometry,MaxTextExtent);
728 for (p=pedantic_geometry; *p != '\0'; )
730 if (isspace((int) ((unsigned char) *p)) != 0)
732 (void) CopyMagickString(p,p+1,MaxTextExtent);
740 (void) CopyMagickString(p,p+1,MaxTextExtent);
746 (void) CopyMagickString(p,p+1,MaxTextExtent);
752 (void) CopyMagickString(p,p+1,MaxTextExtent);
758 (void) CopyMagickString(p,p+1,MaxTextExtent);
764 (void) CopyMagickString(p,p+1,MaxTextExtent);
770 (void) CopyMagickString(p,p+1,MaxTextExtent);
776 (void) CopyMagickString(p,p+1,MaxTextExtent);
812 Parse rho, sigma, xi, psi, and optionally chi.
819 if (LocaleNCompare(p,"0x",2) == 0)
820 value=(double) strtol(p,&q,10);
821 if ((((int) *q) == -41) || (*q == 'x') || (*q == 'X') || (*q == ',') ||
822 (*q == '/') || (*q == ':') || (*q =='\0'))
828 if (LocaleNCompare(p,"0x",2) == 0)
829 value=(double) strtol(p,&p,10);
835 geometry_info->rho=value;
839 if ((((int) *p) == -41) || (*p == 'x') || (*p == 'X') || (*p == ',') ||
840 (*p == '/') || (*p == ':'))
846 while (isspace((int) ((unsigned char) *p)) != 0)
848 if (((((int) *q) != -41) && (*q != 'x') && (*q != 'X')) ||
849 ((*p != '+') && (*p != '-')))
856 geometry_info->sigma=value;
860 while (isspace((int) ((unsigned char) *p)) != 0)
862 if ((*p == '+') || (*p == '-') || (*p == ',') || (*p == '/') || (*p == ':'))
867 if ((*p == ',') || (*p == '/') || (*p == ':'))
876 geometry_info->xi=value;
878 while (isspace((int) ((unsigned char) *p)) != 0)
880 if ((*p == '+') || (*p == '-') || (*p == ',') || (*p == '/') ||
886 if ((*p == ',') || (*p == '/') || (*p == ':'))
895 geometry_info->psi=value;
898 while (isspace((int) ((unsigned char) *p)) != 0)
900 if ((*p == '+') || (*p == '-') || (*p == ',') || (*p == '/') ||
906 if ((*p == ',') || (*p == '/') || (*p == ':'))
915 geometry_info->chi=value;
919 if (strchr(pedantic_geometry,':') != (char *) NULL)
922 Normalize sampling factor (e.g. 4:2:2 => 2x1).
924 geometry_info->rho/=geometry_info->sigma;
925 geometry_info->sigma=1.0;
926 if (geometry_info->xi == 0.0)
927 geometry_info->sigma=2.0;
929 if (((flags & SigmaValue) == 0) && ((flags & XiValue) != 0) &&
930 ((flags & PsiValue) == 0))
933 Support negative height values (e.g. 30x-20).
935 geometry_info->sigma=geometry_info->xi;
936 geometry_info->xi=0.0;
944 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
948 % P a r s e G r a v i t y G e o m e t r y %
952 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
954 % ParseGravityGeometry() returns a region as defined by the geometry string
955 % with respect to the image dimensions and its gravity.
957 % The format of the ParseGravityGeometry method is:
959 % MagickStatusType ParseGravityGeometry(Image *image,const char *geometry,
960 % RectangeInfo *region_info,ExceptionInfo *exception)
962 % A description of each parameter follows:
964 % o geometry: The geometry (e.g. 100x100+10+10).
966 % o region_info: the region as defined by the geometry string with
967 % respect to the image dimensions and its gravity.
969 % o exception: return any errors or warnings in this structure.
972 MagickExport MagickStatusType ParseGravityGeometry(const Image *image,
973 const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
982 SetGeometry(image,region_info);
983 if (image->page.width != 0)
984 region_info->width=image->page.width;
985 if (image->page.height != 0)
986 region_info->height=image->page.height;
987 flags=ParseAbsoluteGeometry(geometry,region_info);
988 if (flags == NoValue)
990 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
991 "InvalidGeometry","`%s'",geometry);
994 if ((flags & PercentValue) != 0)
1006 Geometry is a percentage of the image size.
1008 if (image->gravity != UndefinedGravity)
1009 flags|=XValue | YValue;
1010 status=ParseGeometry(geometry,&geometry_info);
1011 scale.x=geometry_info.rho;
1012 if ((status & RhoValue) == 0)
1014 scale.y=geometry_info.sigma;
1015 if ((status & SigmaValue) == 0)
1017 region_info->width=(size_t) floor((scale.x*image->columns/100.0)+
1019 region_info->height=(size_t) floor((scale.y*image->rows/100.0)+
1023 Adjust offset according to gravity setting.
1025 width=region_info->width;
1026 height=region_info->height;
1028 region_info->width=image->page.width | image->columns;
1030 region_info->height=image->page.height | image->rows;
1031 GravityAdjustGeometry(image->columns,image->rows,image->gravity,region_info);
1032 region_info->width=width;
1033 region_info->height=height;
1038 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1042 + P a r s e M e t a G e o m e t r y %
1046 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1048 % ParseMetaGeometry() is similar to GetGeometry() except the returned
1049 % geometry is modified as determined by the meta characters: %, !, <, >,
1052 % The format of the ParseMetaGeometry method is:
1054 % MagickStatusType ParseMetaGeometry(const char *geometry,ssize_t *x,ssize_t *y,
1055 % size_t *width,size_t *height)
1057 % A description of each parameter follows:
1059 % o geometry: The geometry.
1061 % o x,y: The x and y offset as determined by the geometry specification.
1063 % o width,height: The width and height as determined by the geometry
1068 static inline size_t MagickMax(const size_t x,
1076 MagickExport MagickStatusType ParseMetaGeometry(const char *geometry,ssize_t *x,
1077 ssize_t *y,size_t *width,size_t *height)
1090 Ensure the image geometry is valid.
1092 assert(x != (ssize_t *) NULL);
1093 assert(y != (ssize_t *) NULL);
1094 assert(width != (size_t *) NULL);
1095 assert(height != (size_t *) NULL);
1096 if ((geometry == (char *) NULL) || (*geometry == '\0'))
1098 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",geometry);
1100 Parse geometry using GetGeometry.
1102 SetGeometryInfo(&geometry_info);
1103 former_width=(*width);
1104 former_height=(*height);
1105 flags=GetGeometry(geometry,x,y,width,height);
1106 if ((flags & PercentValue) != 0)
1115 Geometry is a percentage of the image size.
1117 flags=ParseGeometry(geometry,&geometry_info);
1118 scale.x=geometry_info.rho;
1119 if ((flags & RhoValue) == 0)
1121 scale.y=geometry_info.sigma;
1122 if ((flags & SigmaValue) == 0)
1124 *width=(size_t) floor(scale.x*former_width/100.0+0.5);
1127 *height=(size_t) floor(scale.y*former_height/100.0+0.5);
1130 former_width=(*width);
1131 former_height=(*height);
1133 if (((flags & AspectValue) == 0) && ((*width != former_width) ||
1134 (*height != former_height)))
1140 Respect aspect ratio of the image.
1142 if ((former_width == 0) || (former_height == 0))
1145 if (((flags & RhoValue) != 0) && (flags & SigmaValue) != 0)
1147 scale_factor=(MagickRealType) *width/(MagickRealType) former_width;
1148 if ((flags & MinimumValue) == 0)
1150 if (scale_factor > ((MagickRealType) *height/
1151 (MagickRealType) former_height))
1152 scale_factor=(MagickRealType) *height/(MagickRealType)
1156 if (scale_factor < ((MagickRealType) *height/
1157 (MagickRealType) former_height))
1158 scale_factor=(MagickRealType) *height/(MagickRealType)
1162 if ((flags & RhoValue) != 0)
1164 scale_factor=(MagickRealType) *width/(MagickRealType)
1166 if (((flags & MinimumValue) != 0) &&
1167 (scale_factor < ((MagickRealType) *width/
1168 (MagickRealType) former_height)))
1169 scale_factor=(MagickRealType) *width/(MagickRealType)
1174 scale_factor=(MagickRealType) *height/(MagickRealType)
1176 if (((flags & MinimumValue) != 0) &&
1177 (scale_factor < ((MagickRealType) *height/
1178 (MagickRealType) former_width)))
1179 scale_factor=(MagickRealType) *height/(MagickRealType)
1182 *width=MagickMax((size_t) floor(scale_factor*former_width+0.5),
1184 *height=MagickMax((size_t) floor(scale_factor*former_height+0.5),
1187 if ((flags & GreaterValue) != 0)
1189 if (former_width < *width)
1190 *width=former_width;
1191 if (former_height < *height)
1192 *height=former_height;
1194 if ((flags & LessValue) != 0)
1196 if (former_width > *width)
1197 *width=former_width;
1198 if (former_height > *height)
1199 *height=former_height;
1201 if ((flags & AreaValue) != 0)
1211 Geometry is a maximum area in pixels.
1213 (void) ParseGeometry(geometry,&geometry_info);
1214 area=geometry_info.rho;
1215 distance=sqrt((double) former_width*former_height);
1216 scale.x=(double) former_width/(double) (distance/sqrt((double) area));
1217 scale.y=(double) former_height/(double) (distance/sqrt((double) area));
1218 if ((scale.x < (double) *width) || (scale.y < (double) *height))
1220 *width=(size_t) (former_width/(distance/sqrt((double) area)));
1221 *height=(size_t) (former_height/(distance/
1222 sqrt((double) area)));
1224 former_width=(*width);
1225 former_height=(*height);
1231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1235 % P a r s e P a g e G e o m e t r y %
1239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1241 % ParsePageGeometry() returns a region as defined by the geometry string with
1242 % respect to the image dimensions.
1244 % The format of the ParsePageGeometry method is:
1246 % MagickStatusType ParsePageGeometry(const Image *image,
1247 % const char *geometry,RectangeInfo *region_info,
1248 % ExceptionInfo *exception)
1250 % A description of each parameter follows:
1252 % o geometry: The geometry (e.g. 100x100+10+10).
1254 % o region_info: the region as defined by the geometry string with
1255 % respect to the image and its gravity.
1257 % o exception: return any errors or warnings in this structure.
1260 MagickExport MagickStatusType ParsePageGeometry(const Image *image,
1261 const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
1266 SetGeometry(image,region_info);
1267 if (image->page.width != 0)
1268 region_info->width=image->page.width;
1269 if (image->page.height != 0)
1270 region_info->height=image->page.height;
1271 flags=ParseAbsoluteGeometry(geometry,region_info);
1272 if (flags == NoValue)
1274 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1275 "InvalidGeometry","`%s'",geometry);
1278 if ((flags & PercentValue) != 0)
1280 region_info->width=image->columns;
1281 region_info->height=image->rows;
1283 flags=ParseMetaGeometry(geometry,®ion_info->x,®ion_info->y,
1284 ®ion_info->width,®ion_info->height);
1289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1293 % P a r s e R e g i o n G e o m e t r y %
1297 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1299 % ParseRegionGeometry() returns a region as defined by the geometry string
1300 % with respect to the image dimensions and aspect ratio.
1302 % The format of the ParseRegionGeometry method is:
1304 % MagickStatusType ParseRegionGeometry(const Image *image,
1305 % const char *geometry,RectangeInfo *region_info,
1306 % ExceptionInfo *exception)
1308 % A description of each parameter follows:
1310 % o geometry: The geometry (e.g. 100x100+10+10).
1312 % o region_info: the region as defined by the geometry string.
1314 % o exception: return any errors or warnings in this structure.
1317 MagickExport MagickStatusType ParseRegionGeometry(const Image *image,
1318 const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
1323 SetGeometry(image,region_info);
1324 flags=ParseMetaGeometry(geometry,®ion_info->x,®ion_info->y,
1325 ®ion_info->width,®ion_info->height);
1326 if (flags == NoValue)
1327 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1328 "InvalidGeometry","`%s'",geometry);
1333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1337 % S e t G e o m e t r y %
1341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1343 % SetGeometry() sets the geometry to its default values.
1345 % The format of the SetGeometry method is:
1347 % SetGeometry(const Image *image,RectangleInfo *geometry)
1349 % A description of each parameter follows:
1351 % o image: the image.
1353 % o geometry: the geometry.
1356 MagickExport void SetGeometry(const Image *image,RectangleInfo *geometry)
1358 assert(image != (Image *) NULL);
1359 assert(image->signature == MagickSignature);
1360 if (image->debug != MagickFalse)
1361 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1362 assert(geometry != (RectangleInfo *) NULL);
1363 (void) ResetMagickMemory(geometry,0,sizeof(*geometry));
1364 geometry->width=image->columns;
1365 geometry->height=image->rows;
1369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1373 % S e t G e o m e t r y I n f o %
1377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1379 % SetGeometryInfo sets the GeometryInfo structure to its default values.
1381 % The format of the SetGeometryInfo method is:
1383 % SetGeometryInfo(GeometryInfo *geometry_info)
1385 % A description of each parameter follows:
1387 % o geometry_info: the geometry info structure.
1390 MagickExport void SetGeometryInfo(GeometryInfo *geometry_info)
1392 assert(geometry_info != (GeometryInfo *) NULL);
1393 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1394 (void) ResetMagickMemory(geometry_info,0,sizeof(*geometry_info));