MagickCore  7.0.10
geometry.c
Go to the documentation of this file.
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
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 %
11 % %
12 % %
13 % MagickCore Geometry Methods %
14 % %
15 % Software Design %
16 % Cristy %
17 % January 2003 %
18 % %
19 % %
20 % Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
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. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 
39 /*
40  Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/constitute.h"
44 #include "MagickCore/draw.h"
45 #include "MagickCore/exception.h"
47 #include "MagickCore/geometry.h"
49 #include "MagickCore/memory_.h"
51 #include "MagickCore/string_.h"
53 #include "MagickCore/token.h"
54 
55 /*
56 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
57 % %
58 % %
59 % %
60 % G e t G e o m e t r y %
61 % %
62 % %
63 % %
64 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
65 %
66 % GetGeometry() parses a geometry specification and returns the width,
67 % height, x, and y values. It also returns flags that indicates which
68 % of the four values (width, height, x, y) were located in the string, and
69 % whether the x or y values are negative. In addition, there are flags to
70 % report any meta characters (%, !, <, or >).
71 %
72 % The value must form a proper geometry style specification of WxH+X+Y
73 % of integers only, and values can not be separated by comma, colon, or
74 % slash charcaters. See ParseGeometry() below.
75 %
76 % Offsets may be prefixed by multiple signs to make offset string
77 % substitutions easier to handle from shell scripts.
78 % For example: "-10-10", "-+10-+10", or "+-10+-10" will generate negtive
79 % offsets, while "+10+10", "++10++10", or "--10--10" will generate positive
80 % offsets.
81 %
82 % The format of the GetGeometry method is:
83 %
84 % MagickStatusType GetGeometry(const char *geometry,ssize_t *x,ssize_t *y,
85 % size_t *width,size_t *height)
86 %
87 % A description of each parameter follows:
88 %
89 % o geometry: The geometry.
90 %
91 % o x,y: The x and y offset as determined by the geometry specification.
92 %
93 % o width,height: The width and height as determined by the geometry
94 % specification.
95 %
96 */
97 MagickExport MagickStatusType GetGeometry(const char *geometry,ssize_t *x,
98  ssize_t *y,size_t *width,size_t *height)
99 {
100  char
101  *p,
102  pedantic_geometry[MagickPathExtent],
103  *q;
104 
105  double
106  value;
107 
108  int
109  c;
110 
112  flags;
113 
114  /*
115  Remove whitespace and meta characters from geometry specification.
116  */
117  flags=NoValue;
118  if ((geometry == (char *) NULL) || (*geometry == '\0'))
119  return(flags);
120  if (strlen(geometry) >= (MagickPathExtent-1))
121  return(flags);
122  (void) CopyMagickString(pedantic_geometry,geometry,MagickPathExtent);
123  for (p=pedantic_geometry; *p != '\0'; )
124  {
125  if (isspace((int) ((unsigned char) *p)) != 0)
126  {
127  (void) CopyMagickString(p,p+1,MagickPathExtent);
128  continue;
129  }
130  c=(int) *p;
131  switch (c)
132  {
133  case '%':
134  {
135  flags|=PercentValue;
136  (void) CopyMagickString(p,p+1,MagickPathExtent);
137  break;
138  }
139  case '!':
140  {
141  flags|=AspectValue;
142  (void) CopyMagickString(p,p+1,MagickPathExtent);
143  break;
144  }
145  case '<':
146  {
147  flags|=LessValue;
148  (void) CopyMagickString(p,p+1,MagickPathExtent);
149  break;
150  }
151  case '>':
152  {
153  flags|=GreaterValue;
154  (void) CopyMagickString(p,p+1,MagickPathExtent);
155  break;
156  }
157  case '^':
158  {
159  flags|=MinimumValue;
160  (void) CopyMagickString(p,p+1,MagickPathExtent);
161  break;
162  }
163  case '@':
164  {
165  flags|=AreaValue;
166  (void) CopyMagickString(p,p+1,MagickPathExtent);
167  break;
168  }
169  case '(':
170  case ')':
171  {
172  (void) CopyMagickString(p,p+1,MagickPathExtent);
173  break;
174  }
175  case 'x':
176  case 'X':
177  {
178  flags|=SeparatorValue;
179  p++;
180  break;
181  }
182  case '-':
183  case ',':
184  case '+':
185  case '0':
186  case '1':
187  case '2':
188  case '3':
189  case '4':
190  case '5':
191  case '6':
192  case '7':
193  case '8':
194  case '9':
195  case 215:
196  case 'e':
197  case 'E':
198  {
199  p++;
200  break;
201  }
202  case '.':
203  {
204  p++;
205  flags|=DecimalValue;
206  break;
207  }
208  case ':':
209  {
210  p++;
211  flags|=AspectRatioValue;
212  break;
213  }
214  default:
215  return(flags);
216  }
217  }
218  /*
219  Parse width, height, x, and y.
220  */
221  p=pedantic_geometry;
222  if (*p == '\0')
223  return(flags);
224  q=p;
225  value=StringToDouble(p,&q);
226  (void) value;
227  if (LocaleNCompare(p,"0x",2) == 0)
228  value=(double) strtol(p,&q,10);
229  if ((*p != '+') && (*p != '-'))
230  {
231  c=(int) ((unsigned char) *q);
232  if ((c == 215) || (*q == 'x') || (*q == 'X') || (*q == ':') ||
233  (*q == '\0'))
234  {
235  /*
236  Parse width.
237  */
238  q=p;
239  if (width != (size_t *) NULL)
240  {
241  if (LocaleNCompare(p,"0x",2) == 0)
242  *width=(size_t) strtol(p,&p,10);
243  else
244  *width=((size_t) floor(StringToDouble(p,&p)+0.5)) & 0x7fffffff;
245  }
246  if (p != q)
247  flags|=WidthValue;
248  }
249  }
250  if ((*p != '+') && (*p != '-'))
251  {
252  c=(int) ((unsigned char) *p);
253  if ((c == 215) || (*p == 'x') || (*p == 'X') || (*p == ':'))
254  {
255  p++;
256  if ((*p != '+') && (*p != '-'))
257  {
258  /*
259  Parse height.
260  */
261  q=p;
262  if (height != (size_t *) NULL)
263  *height=((size_t) floor(StringToDouble(p,&p)+0.5)) & 0x7fffffff;
264  if (p != q)
265  flags|=HeightValue;
266  }
267  }
268  }
269  if ((*p == '+') || (*p == '-'))
270  {
271  /*
272  Parse x value.
273  */
274  while ((*p == '+') || (*p == '-'))
275  {
276  if (*p == '-')
277  flags^=XNegative; /* negate sign */
278  p++;
279  }
280  q=p;
281  if (x != (ssize_t *) NULL)
282  *x=((ssize_t) ceil(StringToDouble(p,&p)-0.5)) & 0x7fffffff;
283  if (p != q)
284  {
285  flags|=XValue;
286  if (((flags & XNegative) != 0) && (x != (ssize_t *) NULL))
287  *x=(-*x);
288  }
289  }
290  if ((*p == '+') || (*p == '-'))
291  {
292  /*
293  Parse y value.
294  */
295  while ((*p == '+') || (*p == '-'))
296  {
297  if (*p == '-')
298  flags^=YNegative; /* negate sign */
299  p++;
300  }
301  q=p;
302  if (y != (ssize_t *) NULL)
303  *y=((ssize_t) ceil(StringToDouble(p,&p)-0.5)) & 0x7fffffff;
304  if (p != q)
305  {
306  flags|=YValue;
307  if (((flags & YNegative) != 0) && (y != (ssize_t *) NULL))
308  *y=(-*y);
309  }
310  }
311  if ((flags & PercentValue) != 0)
312  {
313  if (((flags & SeparatorValue) == 0) && ((flags & HeightValue) == 0))
314  {
315  if ((height != (size_t *) NULL) && (width != (size_t *) NULL))
316  *height=(*width);
317  flags|=HeightValue;
318  }
319  if (((flags & SeparatorValue) != 0) && ((flags & WidthValue) == 0) &&
320  (height != (size_t *) NULL) && (width != (size_t *) NULL))
321  *width=(*height);
322  }
323 #if 0
324  /* Debugging Geometry */
325  (void) fprintf(stderr,"GetGeometry...\n");
326  (void) fprintf(stderr,"Input: %s\n",geometry);
327  (void) fprintf(stderr,"Flags: %c %c %s %s\n",
328  (flags & WidthValue) ? 'W' : ' ',(flags & HeightValue) ? 'H' : ' ',
329  (flags & XValue) ? ((flags & XNegative) ? "-X" : "+X") : " ",
330  (flags & YValue) ? ((flags & YNegative) ? "-Y" : "+Y") : " ");
331  (void) fprintf(stderr,"Geometry: %ldx%ld%+ld%+ld\n",(long) *width,(long)
332  *height,(long) *x,(long) *y);
333 #endif
334  return(flags);
335 }
336 
337 /*
338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
339 % %
340 % %
341 % %
342 % G e t P a g e G e o m e t r y %
343 % %
344 % %
345 % %
346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347 %
348 % GetPageGeometry() replaces any page mneumonic with the equivalent size in
349 % picas.
350 %
351 % The format of the GetPageGeometry method is:
352 %
353 % char *GetPageGeometry(const char *page_geometry)
354 %
355 % A description of each parameter follows.
356 %
357 % o page_geometry: Specifies a pointer to an array of characters. The
358 % string is either a Postscript page name (e.g. A4) or a postscript page
359 % geometry (e.g. 612x792+36+36).
360 %
361 */
362 MagickExport char *GetPageGeometry(const char *page_geometry)
363 {
364 #define MagickPageSize(name,geometry) { (name), sizeof(name)-1, (geometry) }
365 
366  typedef struct _PageInfo
367  {
368  const char
369  name[12];
370 
371  size_t
372  extent;
373 
374  const char
375  geometry[10];
376  } PageInfo;
377 
378  static const PageInfo
379  PageSizes[] =
380  {
381  MagickPageSize("4x6", "288x432"),
382  MagickPageSize("5x7", "360x504"),
383  MagickPageSize("7x9", "504x648"),
384  MagickPageSize("8x10", "576x720"),
385  MagickPageSize("9x11", "648x792"),
386  MagickPageSize("9x12", "648x864"),
387  MagickPageSize("10x13", "720x936"),
388  MagickPageSize("10x14", "720x1008"),
389  MagickPageSize("11x17", "792x1224"),
390  MagickPageSize("4A0", "4768x6741"),
391  MagickPageSize("2A0", "3370x4768"),
392  MagickPageSize("a0", "2384x3370"),
393  MagickPageSize("a1", "1684x2384"),
394  MagickPageSize("a2", "1191x1684"),
395  MagickPageSize("a3", "842x1191"),
396  MagickPageSize("a4", "595x842"),
397  MagickPageSize("a4small", "595x842"),
398  MagickPageSize("a5", "420x595"),
399  MagickPageSize("a6", "298x420"),
400  MagickPageSize("a7", "210x298"),
401  MagickPageSize("a8", "147x210"),
402  MagickPageSize("a9", "105x147"),
403  MagickPageSize("a10", "74x105"),
404  MagickPageSize("archa", "648x864"),
405  MagickPageSize("archb", "864x1296"),
406  MagickPageSize("archC", "1296x1728"),
407  MagickPageSize("archd", "1728x2592"),
408  MagickPageSize("arche", "2592x3456"),
409  MagickPageSize("b0", "2920x4127"),
410  MagickPageSize("b1", "2064x2920"),
411  MagickPageSize("b10", "91x127"),
412  MagickPageSize("b2", "1460x2064"),
413  MagickPageSize("b3", "1032x1460"),
414  MagickPageSize("b4", "729x1032"),
415  MagickPageSize("b5", "516x729"),
416  MagickPageSize("b6", "363x516"),
417  MagickPageSize("b7", "258x363"),
418  MagickPageSize("b8", "181x258"),
419  MagickPageSize("b9", "127x181"),
420  MagickPageSize("c0", "2599x3676"),
421  MagickPageSize("c1", "1837x2599"),
422  MagickPageSize("c2", "1298x1837"),
423  MagickPageSize("c3", "918x1296"),
424  MagickPageSize("c4", "649x918"),
425  MagickPageSize("c5", "459x649"),
426  MagickPageSize("c6", "323x459"),
427  MagickPageSize("c7", "230x323"),
428  MagickPageSize("csheet", "1224x1584"),
429  MagickPageSize("dsheet", "1584x2448"),
430  MagickPageSize("esheet", "2448x3168"),
431  MagickPageSize("executive", "540x720"),
432  MagickPageSize("flsa", "612x936"),
433  MagickPageSize("flse", "612x936"),
434  MagickPageSize("folio", "612x936"),
435  MagickPageSize("halfletter", "396x612"),
436  MagickPageSize("isob0", "2835x4008"),
437  MagickPageSize("isob1", "2004x2835"),
438  MagickPageSize("isob10", "88x125"),
439  MagickPageSize("isob2", "1417x2004"),
440  MagickPageSize("isob3", "1001x1417"),
441  MagickPageSize("isob4", "709x1001"),
442  MagickPageSize("isob5", "499x709"),
443  MagickPageSize("isob6", "354x499"),
444  MagickPageSize("isob7", "249x354"),
445  MagickPageSize("isob8", "176x249"),
446  MagickPageSize("isob9", "125x176"),
447  MagickPageSize("jisb0", "1030x1456"),
448  MagickPageSize("jisb1", "728x1030"),
449  MagickPageSize("jisb2", "515x728"),
450  MagickPageSize("jisb3", "364x515"),
451  MagickPageSize("jisb4", "257x364"),
452  MagickPageSize("jisb5", "182x257"),
453  MagickPageSize("jisb6", "128x182"),
454  MagickPageSize("ledger", "1224x792"),
455  MagickPageSize("legal", "612x1008"),
456  MagickPageSize("letter", "612x792"),
457  MagickPageSize("lettersmall", "612x792"),
458  MagickPageSize("monarch", "279x540"),
459  MagickPageSize("quarto", "610x780"),
460  MagickPageSize("statement", "396x612"),
461  MagickPageSize("tabloid", "792x1224")
462  };
463 
464  char
465  page[MaxTextExtent];
466 
467  ssize_t
468  i;
469 
470  assert(page_geometry != (char *) NULL);
471  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",page_geometry);
472  (void) CopyMagickString(page,page_geometry,MaxTextExtent);
473  for (i=0; i < (ssize_t) (sizeof(PageSizes)/sizeof(PageSizes[0])); i++)
474  {
475  int
476  status;
477 
478  status=LocaleNCompare(PageSizes[i].name,page_geometry,PageSizes[i].extent);
479  if (status == 0)
480  {
482  flags;
483 
485  geometry;
486 
487  /*
488  Replace mneumonic with the equivalent size in dots-per-inch.
489  */
490  (void) FormatLocaleString(page,MaxTextExtent,"%s%.80s",
491  PageSizes[i].geometry,page_geometry+PageSizes[i].extent);
492  flags=GetGeometry(page,&geometry.x,&geometry.y,&geometry.width,
493  &geometry.height);
494  if ((flags & GreaterValue) == 0)
495  (void) ConcatenateMagickString(page,">",MaxTextExtent);
496  break;
497  }
498  }
499  return(AcquireString(page));
500 }
501 
502 /*
503 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
504 % %
505 % %
506 % %
507 % G r a v i t y A d j u s t G e o m e t r y %
508 % %
509 % %
510 % %
511 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
512 %
513 % GravityAdjustGeometry() adjusts the offset of a region with regard to the
514 % given: width, height and gravity; against which it is positioned.
515 %
516 % The region should also have an appropriate width and height to correctly
517 % set the right offset of the top left corner of the region.
518 %
519 % The format of the GravityAdjustGeometry method is:
520 %
521 % void GravityAdjustGeometry(const size_t width, const size_t height,
522 % const GravityType gravity,RectangleInfo *region);
523 %
524 % A description of each parameter follows:
525 %
526 % o width, height: the larger area the region is relative to
527 %
528 % o gravity: the edge/corner the current offset is relative to
529 %
530 % o region: The region requiring a offset adjustment relative to gravity
531 %
532 */
533 MagickExport void GravityAdjustGeometry(const size_t width,
534  const size_t height,const GravityType gravity,RectangleInfo *region)
535 {
536  if (region->height == 0)
537  region->height=height;
538  if (region->width == 0)
539  region->width=width;
540  switch (gravity)
541  {
542  case NorthEastGravity:
543  case EastGravity:
544  case SouthEastGravity:
545  {
546  region->x=(ssize_t) (width-region->width-region->x);
547  break;
548  }
549  case NorthGravity:
550  case SouthGravity:
551  case CenterGravity:
552  {
553  region->x+=(ssize_t) (width/2-region->width/2);
554  break;
555  }
556  case ForgetGravity:
557  case NorthWestGravity:
558  case WestGravity:
559  case SouthWestGravity:
560  default:
561  break;
562  }
563  switch (gravity)
564  {
565  case SouthWestGravity:
566  case SouthGravity:
567  case SouthEastGravity:
568  {
569  region->y=(ssize_t) (height-region->height-region->y);
570  break;
571  }
572  case EastGravity:
573  case WestGravity:
574  case CenterGravity:
575  {
576  region->y+=(ssize_t) (height/2-region->height/2);
577  break;
578  }
579  case ForgetGravity:
580  case NorthWestGravity:
581  case NorthGravity:
582  case NorthEastGravity:
583  default:
584  break;
585  }
586  return;
587 }
588 
589 /*
590 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
591 % %
592 % %
593 % %
594 + I s G e o m e t r y %
595 % %
596 % %
597 % %
598 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
599 %
600 % IsGeometry() returns MagickTrue if the geometry specification is valid.
601 % Examples are 100, 100x200, x200, 100x200+10+20, +10+20, 200%, 200x200!, etc.
602 %
603 % The format of the IsGeometry method is:
604 %
605 % MagickBooleanType IsGeometry(const char *geometry)
606 %
607 % A description of each parameter follows:
608 %
609 % o geometry: This string is the geometry specification.
610 %
611 */
613 {
615  geometry_info;
616 
618  flags;
619 
620  if (geometry == (const char *) NULL)
621  return(MagickFalse);
622  flags=ParseGeometry(geometry,&geometry_info);
623  return(flags != NoValue ? MagickTrue : MagickFalse);
624 }
625 
626 /*
627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
628 % %
629 % %
630 % %
631 + I s S c e n e G e o m e t r y %
632 % %
633 % %
634 % %
635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
636 %
637 % IsSceneGeometry() returns MagickTrue if the geometry is a valid scene
638 % specification (e.g. [1], [1-9], [1,7,4]).
639 %
640 % The format of the IsSceneGeometry method is:
641 %
642 % MagickBooleanType IsSceneGeometry(const char *geometry,
643 % const MagickBooleanType pedantic)
644 %
645 % A description of each parameter follows:
646 %
647 % o geometry: This string is the geometry specification.
648 %
649 % o pedantic: A value other than 0 invokes a more restrictive set of
650 % conditions for a valid specification (e.g. [1], [1-4], [4-1]).
651 %
652 */
654  const MagickBooleanType pedantic)
655 {
656  char
657  *p;
658 
659  double
660  value;
661 
662  if (geometry == (const char *) NULL)
663  return(MagickFalse);
664  p=(char *) geometry;
665  value=StringToDouble(geometry,&p);
666  (void) value;
667  if (p == geometry)
668  return(MagickFalse);
669  if (strspn(geometry,"0123456789-, ") != strlen(geometry))
670  return(MagickFalse);
671  if ((pedantic != MagickFalse) && (strchr(geometry,',') != (char *) NULL))
672  return(MagickFalse);
673  return(MagickTrue);
674 }
675 
676 /*
677 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
678 % %
679 % %
680 % %
681 % P a r s e A b s o l u t e G e o m e t r y %
682 % %
683 % %
684 % %
685 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
686 %
687 % ParseAbsoluteGeometry() returns a region as defined by the geometry string,
688 % without any modification by percentages or gravity.
689 %
690 % It currently just a wrapper around GetGeometry(), but may be expanded in
691 % the future to handle other positioning information.
692 %
693 % The format of the ParseAbsoluteGeometry method is:
694 %
695 % MagickStatusType ParseAbsoluteGeometry(const char *geometry,
696 % RectangleInfo *region_info)
697 %
698 % A description of each parameter follows:
699 %
700 % o geometry: The geometry string (e.g. "100x100+10+10").
701 %
702 % o region_info: the region as defined by the geometry string.
703 %
704 */
706  RectangleInfo *region_info)
707 {
709  flags;
710 
711  flags=GetGeometry(geometry,&region_info->x,&region_info->y,
712  &region_info->width,&region_info->height);
713  return(flags);
714 }
715 
716 /*
717 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
718 % %
719 % %
720 % %
721 % P a r s e A f f i n e G e o m e t r y %
722 % %
723 % %
724 % %
725 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
726 %
727 % ParseAffineGeometry() returns an affine matrix as defined by a string of 4
728 % to 6 comma/space separated floating point values.
729 %
730 % The affine matrix determinant is checked for validity of the values.
731 %
732 % The format of the ParseAffineGeometry method is:
733 %
734 % MagickStatusType ParseAffineGeometry(const char *geometry,
735 % AffineMatrix *affine_matrix,ExceptionInfo *exception)
736 %
737 % A description of each parameter follows:
738 %
739 % o geometry: The geometry string (e.g. "1.0,0.0,0.0,1.0,3.2,1.2").
740 %
741 % o affine_matrix: the affine matrix as defined by the geometry string.
742 %
743 % o exception: return any errors or warnings in this structure.
744 %
745 */
747  AffineMatrix *affine_matrix,ExceptionInfo *exception)
748 {
749  char
750  token[MagickPathExtent];
751 
752  const char
753  *p;
754 
755  double
756  determinant;
757 
759  flags;
760 
761  ssize_t
762  i;
763 
764  GetAffineMatrix(affine_matrix);
765  flags=NoValue;
766  p=(char *) geometry;
767  for (i=0; (*p != '\0') && (i < 6); i++)
768  {
769  (void) GetNextToken(p,&p,MagickPathExtent,token);
770  if (*token == ',')
771  (void) GetNextToken(p,&p,MagickPathExtent,token);
772  switch (i)
773  {
774  case 0:
775  {
776  affine_matrix->sx=StringToDouble(token,(char **) NULL);
777  break;
778  }
779  case 1:
780  {
781  affine_matrix->rx=StringToDouble(token,(char **) NULL);
782  break;
783  }
784  case 2:
785  {
786  affine_matrix->ry=StringToDouble(token,(char **) NULL);
787  break;
788  }
789  case 3:
790  {
791  affine_matrix->sy=StringToDouble(token,(char **) NULL);
792  break;
793  }
794  case 4:
795  {
796  affine_matrix->tx=StringToDouble(token,(char **) NULL);
797  flags|=XValue;
798  break;
799  }
800  case 5:
801  {
802  affine_matrix->ty=StringToDouble(token,(char **) NULL);
803  flags|=YValue;
804  break;
805  }
806  }
807  }
808  determinant=(affine_matrix->sx*affine_matrix->sy-affine_matrix->rx*
809  affine_matrix->ry);
810  if (fabs(determinant) < MagickEpsilon)
812  "InvalidArgument","'%s' : 'Indeterminate Matrix'",geometry);
813  return(flags);
814 }
815 
816 /*
817 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
818 % %
819 % %
820 % %
821 % P a r s e G e o m e t r y %
822 % %
823 % %
824 % %
825 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
826 %
827 % ParseGeometry() parses a geometry specification and returns the sigma,
828 % rho, xi, and psi values. It also returns flags that indicates which
829 % of the four values (sigma, rho, xi, psi) were located in the string, and
830 % whether the xi or pi values are negative.
831 %
832 % In addition, it reports if there are any of meta characters (%, !, <, >, @,
833 % and ^) flags present. It does not report the location of the percentage
834 % relative to the values.
835 %
836 % Values may also be separated by commas, colons, or slashes, and offsets.
837 % Offsets may be prefixed by multiple signs to make offset string
838 % substitutions easier to handle from shell scripts.
839 % For example: "-10-10", "-+10-+10", or "+-10+-10" will generate negtive
840 % offsets, while "+10+10", "++10++10", or "--10--10" will generate positive
841 % offsets.
842 %
843 % The format of the ParseGeometry method is:
844 %
845 % MagickStatusType ParseGeometry(const char *geometry,
846 % GeometryInfo *geometry_info)
847 %
848 % A description of each parameter follows:
849 %
850 % o geometry: The geometry string (e.g. "100x100+10+10").
851 %
852 % o geometry_info: returns the parsed width/height/x/y in this structure.
853 %
854 */
856  GeometryInfo *geometry_info)
857 {
858  char
859  *p,
860  pedantic_geometry[MagickPathExtent],
861  *q;
862 
863  double
864  value;
865 
867  coordinate;
868 
869  int
870  c;
871 
873  flags;
874 
875  /*
876  Remove whitespaces meta characters from geometry specification.
877  */
878  assert(geometry_info != (GeometryInfo *) NULL);
879  (void) memset(geometry_info,0,sizeof(*geometry_info));
880  flags=NoValue;
881  if ((geometry == (char *) NULL) || (*geometry == '\0'))
882  return(flags);
883  if (strlen(geometry) >= (MagickPathExtent-1))
884  return(flags);
885  c=sscanf(geometry,"%lf%*[ ,]%lf%*[ ,]%lf%*[ ,]%lf",&coordinate.rho,
886  &coordinate.sigma,&coordinate.xi,&coordinate.psi);
887  if (c == 4)
888  {
889  /*
890  Special case: coordinate (e.g. 0,0 255,255).
891  */
892  geometry_info->rho=coordinate.rho;
893  geometry_info->sigma=coordinate.sigma;
894  geometry_info->xi=coordinate.xi;
895  geometry_info->psi=coordinate.psi;
896  flags|=RhoValue | SigmaValue | XiValue | PsiValue;
897  return(flags);
898  }
899  (void) CopyMagickString(pedantic_geometry,geometry,MagickPathExtent);
900  for (p=pedantic_geometry; *p != '\0'; )
901  {
902  c=(int) ((unsigned char) *p);
903  if (isspace((int) ((unsigned char) c)) != 0)
904  {
905  (void) CopyMagickString(p,p+1,MagickPathExtent);
906  continue;
907  }
908  switch (c)
909  {
910  case '%':
911  {
912  flags|=PercentValue;
913  (void) CopyMagickString(p,p+1,MagickPathExtent);
914  break;
915  }
916  case '!':
917  {
918  flags|=AspectValue;
919  (void) CopyMagickString(p,p+1,MagickPathExtent);
920  break;
921  }
922  case '<':
923  {
924  flags|=LessValue;
925  (void) CopyMagickString(p,p+1,MagickPathExtent);
926  break;
927  }
928  case '>':
929  {
930  flags|=GreaterValue;
931  (void) CopyMagickString(p,p+1,MagickPathExtent);
932  break;
933  }
934  case '^':
935  {
936  flags|=MinimumValue;
937  (void) CopyMagickString(p,p+1,MagickPathExtent);
938  break;
939  }
940  case '@':
941  {
942  flags|=AreaValue;
943  (void) CopyMagickString(p,p+1,MagickPathExtent);
944  break;
945  }
946  case '(':
947  {
948  if (*(p+1) == ')')
949  return(flags);
950  }
951  case ')':
952  {
953  (void) CopyMagickString(p,p+1,MagickPathExtent);
954  break;
955  }
956  case 'x':
957  case 'X':
958  {
959  flags|=SeparatorValue;
960  p++;
961  break;
962  }
963  case '-':
964  case '+':
965  case ',':
966  case '0':
967  case '1':
968  case '2':
969  case '3':
970  case '4':
971  case '5':
972  case '6':
973  case '7':
974  case '8':
975  case '9':
976  case '/':
977  case 215:
978  case 'e':
979  case 'E':
980  {
981  p++;
982  break;
983  }
984  case '.':
985  {
986  p++;
987  flags|=DecimalValue;
988  break;
989  }
990  case ':':
991  {
992  p++;
993  flags|=AspectRatioValue;
994  break;
995  }
996  default:
997  return(NoValue);
998  }
999  }
1000  /*
1001  Parse rho, sigma, xi, psi, and optionally chi.
1002  */
1003  p=pedantic_geometry;
1004  if (*p == '\0')
1005  return(flags);
1006  q=p;
1007  value=StringToDouble(p,&q);
1008  if (LocaleNCompare(p,"0x",2) == 0)
1009  (void) strtol(p,&q,10);
1010  c=(int) ((unsigned char) *q);
1011  if ((c == 215) || (*q == 'x') || (*q == 'X') || (*q == ':') ||
1012  (*q == ',') || (*q == '/') || (*q =='\0'))
1013  {
1014  /*
1015  Parse rho.
1016  */
1017  q=p;
1018  if (LocaleNCompare(p,"0x",2) == 0)
1019  value=(double) strtol(p,&p,10);
1020  else
1021  value=StringToDouble(p,&p);
1022  if (p != q)
1023  {
1024  flags|=RhoValue;
1025  geometry_info->rho=value;
1026  }
1027  }
1028  q=p;
1029  c=(int) ((unsigned char) *p);
1030  if ((c == 215) || (*p == 'x') || (*p == 'X') || (*p == ':') || (*p == ',') ||
1031  (*p == '/'))
1032  {
1033  /*
1034  Parse sigma.
1035  */
1036  p++;
1037  while (isspace((int) ((unsigned char) *p)) != 0)
1038  p++;
1039  c=(int) ((unsigned char) *q);
1040  if (((c != 215) && (*q != 'x') && (*q != 'X') && (*q != ':')) ||
1041  ((*p != '+') && (*p != '-')))
1042  {
1043  q=p;
1044  value=StringToDouble(p,&p);
1045  if (p != q)
1046  {
1047  flags|=SigmaValue;
1048  geometry_info->sigma=value;
1049  }
1050  }
1051  }
1052  while (isspace((int) ((unsigned char) *p)) != 0)
1053  p++;
1054  if ((*p == '+') || (*p == '-') || (*p == ',') || (*p == '/') || (*p == ':'))
1055  {
1056  /*
1057  Parse xi value.
1058  */
1059  if ((*p == ',') || (*p == '/') || (*p == ':') )
1060  p++;
1061  while ((*p == '+') || (*p == '-'))
1062  {
1063  if (*p == '-')
1064  flags^=XiNegative; /* negate sign */
1065  p++;
1066  }
1067  q=p;
1068  value=StringToDouble(p,&p);
1069  if (p != q)
1070  {
1071  flags|=XiValue;
1072  if ((flags & XiNegative) != 0)
1073  value=(-value);
1074  geometry_info->xi=value;
1075  }
1076  while (isspace((int) ((unsigned char) *p)) != 0)
1077  p++;
1078  if ((*p == '+') || (*p == '-') || (*p == ',') || (*p == '/') ||
1079  (*p == ':'))
1080  {
1081  /*
1082  Parse psi value.
1083  */
1084  if ((*p == ',') || (*p == '/') || (*p == ':'))
1085  p++;
1086  while ((*p == '+') || (*p == '-'))
1087  {
1088  if (*p == '-')
1089  flags^=PsiNegative; /* negate sign */
1090  p++;
1091  }
1092  q=p;
1093  value=StringToDouble(p,&p);
1094  if (p != q)
1095  {
1096  flags|=PsiValue;
1097  if ((flags & PsiNegative) != 0)
1098  value=(-value);
1099  geometry_info->psi=value;
1100  }
1101  }
1102  while (isspace((int) ((unsigned char) *p)) != 0)
1103  p++;
1104  if ((*p == '+') || (*p == '-') || (*p == ',') || (*p == '/') ||
1105  (*p == ':'))
1106  {
1107  /*
1108  Parse chi value.
1109  */
1110  if ((*p == ',') || (*p == '/') || (*p == ':'))
1111  p++;
1112  while ((*p == '+') || (*p == '-'))
1113  {
1114  if (*p == '-')
1115  flags^=ChiNegative; /* negate sign */
1116  p++;
1117  }
1118  q=p;
1119  value=StringToDouble(p,&p);
1120  if (p != q)
1121  {
1122  flags|=ChiValue;
1123  if ((flags & ChiNegative) != 0)
1124  value=(-value);
1125  geometry_info->chi=value;
1126  }
1127  }
1128  }
1129  if (strchr(pedantic_geometry,':') != (char *) NULL)
1130  {
1131  /*
1132  Normalize sampling factor (e.g. 4:2:2 => 2x1).
1133  */
1134  if ((flags & SigmaValue) != 0)
1135  geometry_info->rho*=PerceptibleReciprocal(geometry_info->sigma);
1136  geometry_info->sigma=1.0;
1137  if (((flags & XiValue) != 0) && (geometry_info->xi == 0.0))
1138  geometry_info->sigma=2.0;
1139  }
1140  if (((flags & RhoValue) != 0) && ((flags & SigmaValue) == 0) &&
1141  ((flags & XiValue) != 0) && ((flags & XiNegative) != 0))
1142  {
1143  if ((flags & PsiValue) == 0)
1144  {
1145  /*
1146  Support negative height values (e.g. 30x-20).
1147  */
1148  geometry_info->sigma=geometry_info->xi;
1149  geometry_info->xi=0.0;
1150  flags|=SigmaValue;
1151  flags&=(~XiValue);
1152  }
1153  else
1154  if ((flags & ChiValue) == 0)
1155  {
1156  /*
1157  Support negative height values (e.g. 30x-20+10).
1158  */
1159  geometry_info->sigma=geometry_info->xi;
1160  geometry_info->xi=geometry_info->psi;
1161  flags|=SigmaValue;
1162  flags|=XiValue;
1163  flags&=(~PsiValue);
1164  }
1165  else
1166  {
1167  /*
1168  Support negative height values (e.g. 30x-20+10+10).
1169  */
1170  geometry_info->sigma=geometry_info->xi;
1171  geometry_info->xi=geometry_info->psi;
1172  geometry_info->psi=geometry_info->chi;
1173  flags|=SigmaValue;
1174  flags|=XiValue;
1175  flags|=PsiValue;
1176  flags&=(~ChiValue);
1177  }
1178  }
1179  if ((flags & PercentValue) != 0)
1180  {
1181  if (((flags & SeparatorValue) == 0) && ((flags & SigmaValue) == 0))
1182  geometry_info->sigma=geometry_info->rho;
1183  if (((flags & SeparatorValue) != 0) && ((flags & RhoValue) == 0))
1184  geometry_info->rho=geometry_info->sigma;
1185  }
1186 #if 0
1187  /* Debugging Geometry */
1188  (void) fprintf(stderr,"ParseGeometry...\n");
1189  (void) fprintf(stderr,"Flags: %c %c %s %s %s\n",
1190  (flags & RhoValue) ? 'W' : ' ',(flags & SigmaValue) ? 'H' : ' ',
1191  (flags & XiValue) ? ((flags & XiNegative) ? "-X" : "+X") : " ",
1192  (flags & PsiValue) ? ((flags & PsiNegative) ? "-Y" : "+Y") : " ",
1193  (flags & ChiValue) ? ((flags & ChiNegative) ? "-Z" : "+Z") : " ");
1194  (void) fprintf(stderr,"Geometry: %lg,%lg,%lg,%lg,%lg\n",geometry_info->rho,
1195  geometry_info->sigma,geometry_info->xi,geometry_info->psi,
1196  geometry_info->chi);
1197 #endif
1198  return(flags);
1199 }
1200 
1201 /*
1202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1203 % %
1204 % %
1205 % %
1206 % P a r s e G r a v i t y G e o m e t r y %
1207 % %
1208 % %
1209 % %
1210 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1211 %
1212 % ParseGravityGeometry() returns a region as defined by the geometry string
1213 % with respect to the given image page (canvas) dimensions and the images
1214 % gravity setting.
1215 %
1216 % This is typically used for specifing a area within a given image for
1217 % cropping images to a smaller size, chopping out rows and or columns, or
1218 % resizing and positioning overlay images.
1219 %
1220 % Percentages are relative to image size and not page size, and are set to
1221 % nearest integer (pixel) size.
1222 %
1223 % The format of the ParseGravityGeometry method is:
1224 %
1225 % MagickStatusType ParseGravityGeometry(Image *image,const char *geometry,
1226 % RectangeInfo *region_info,ExceptionInfo *exception)
1227 %
1228 % A description of each parameter follows:
1229 %
1230 % o geometry: The geometry string (e.g. "100x100+10+10").
1231 %
1232 % o region_info: the region as defined by the geometry string with respect
1233 % to the image dimensions and its gravity.
1234 %
1235 % o exception: return any errors or warnings in this structure.
1236 %
1237 */
1239  const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
1240 {
1242  flags;
1243 
1244  size_t
1245  height,
1246  width;
1247 
1248  SetGeometry(image,region_info);
1249  if (image->page.width != 0)
1250  region_info->width=image->page.width;
1251  if (image->page.height != 0)
1252  region_info->height=image->page.height;
1253  flags=ParseAbsoluteGeometry(geometry,region_info);
1254  if (flags == NoValue)
1255  {
1257  "InvalidGeometry","`%s'",geometry);
1258  return(flags);
1259  }
1260  if ((flags & PercentValue) != 0)
1261  {
1262  GeometryInfo
1263  geometry_info;
1264 
1266  status;
1267 
1268  PointInfo
1269  scale;
1270 
1271  /*
1272  Geometry is a percentage of the image size, not canvas size
1273  */
1274  if (image->gravity != UndefinedGravity)
1275  flags|=XValue | YValue;
1276  status=ParseGeometry(geometry,&geometry_info);
1277  scale.x=geometry_info.rho;
1278  if ((status & RhoValue) == 0)
1279  scale.x=100.0;
1280  scale.y=geometry_info.sigma;
1281  if ((status & SigmaValue) == 0)
1282  scale.y=scale.x;
1283  region_info->width=(size_t) floor((scale.x*image->columns/100.0)+0.5);
1284  region_info->height=(size_t) floor((scale.y*image->rows/100.0)+0.5);
1285  }
1286  if ((flags & AspectRatioValue) != 0)
1287  {
1288  double
1289  geometry_ratio,
1290  image_ratio;
1291 
1292  GeometryInfo
1293  geometry_info;
1294 
1295  /*
1296  Geometry is a relative to image size and aspect ratio.
1297  */
1298  if (image->gravity != UndefinedGravity)
1299  flags|=XValue | YValue;
1300  (void) ParseGeometry(geometry,&geometry_info);
1301  geometry_ratio=geometry_info.rho;
1302  image_ratio=(double) image->columns/image->rows;
1303  if (geometry_ratio >= image_ratio)
1304  {
1305  region_info->width=image->columns;
1306  region_info->height=(size_t) floor((double) (image->rows*image_ratio/
1307  geometry_ratio)+0.5);
1308  }
1309  else
1310  {
1311  region_info->width=(size_t) floor((double) (image->columns*
1312  geometry_ratio/image_ratio)+0.5);
1313  region_info->height=image->rows;
1314  }
1315  }
1316  /*
1317  Adjust offset according to gravity setting.
1318  */
1319  width=region_info->width;
1320  height=region_info->height;
1321  if (width == 0)
1322  region_info->width=image->page.width | image->columns;
1323  if (height == 0)
1324  region_info->height=image->page.height | image->rows;
1325  GravityAdjustGeometry(image->columns,image->rows,image->gravity,region_info);
1326  region_info->width=width;
1327  region_info->height=height;
1328  return(flags);
1329 }
1330 
1331 /*
1332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1333 % %
1334 % %
1335 % %
1336 + P a r s e M e t a G e o m e t r y %
1337 % %
1338 % %
1339 % %
1340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1341 %
1342 % ParseMetaGeometry() is similar to GetGeometry() except the returned
1343 % geometry is modified as determined by the meta characters: %, !, <, >, @,
1344 % :, and ^ in relation to image resizing.
1345 %
1346 % Final image dimensions are adjusted so as to preserve the aspect ratio as
1347 % much as possible, while generating a integer (pixel) size, and fitting the
1348 % image within the specified geometry width and height.
1349 %
1350 % Flags are interpreted...
1351 % % geometry size is given percentage of original width and height given
1352 % ! do not try to preserve aspect ratio
1353 % < only enlarge images smaller that geometry
1354 % > only shrink images larger than geometry
1355 % @ fit image to contain at most this many pixels
1356 % : width and height denotes an aspect ratio
1357 % ^ contain the given geometry given, (minimal dimensions given)
1358 %
1359 % The format of the ParseMetaGeometry method is:
1360 %
1361 % MagickStatusType ParseMetaGeometry(const char *geometry,ssize_t *x,
1362 % ssize_t *y, size_t *width,size_t *height)
1363 %
1364 % A description of each parameter follows:
1365 %
1366 % o geometry: The geometry string (e.g. "100x100+10+10").
1367 %
1368 % o x,y: The x and y offset, set according to the geometry specification.
1369 %
1370 % o width,height: The width and height of original image, modified by
1371 % the given geometry specification.
1372 %
1373 */
1374 MagickExport MagickStatusType ParseMetaGeometry(const char *geometry,ssize_t *x,
1375  ssize_t *y,size_t *width,size_t *height)
1376 {
1377  GeometryInfo
1378  geometry_info;
1379 
1381  flags;
1382 
1383  size_t
1384  former_height,
1385  former_width;
1386 
1387  /*
1388  Ensure the image geometry is valid.
1389  */
1390  assert(x != (ssize_t *) NULL);
1391  assert(y != (ssize_t *) NULL);
1392  assert(width != (size_t *) NULL);
1393  assert(height != (size_t *) NULL);
1394  if ((geometry == (char *) NULL) || (*geometry == '\0'))
1395  return(NoValue);
1396  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",geometry);
1397  /*
1398  Parse geometry using GetGeometry.
1399  */
1400  SetGeometryInfo(&geometry_info);
1401  former_width=(*width);
1402  former_height=(*height);
1403  flags=GetGeometry(geometry,x,y,width,height);
1404  if ((flags & PercentValue) != 0)
1405  {
1407  percent_flags;
1408 
1409  PointInfo
1410  scale;
1411 
1412  /*
1413  Geometry is a percentage of the image size.
1414  */
1415  percent_flags=ParseGeometry(geometry,&geometry_info);
1416  scale.x=geometry_info.rho;
1417  if ((percent_flags & RhoValue) == 0)
1418  scale.x=100.0;
1419  scale.y=geometry_info.sigma;
1420  if ((percent_flags & SigmaValue) == 0)
1421  scale.y=scale.x;
1422  *width=(size_t) floor(scale.x*former_width/100.0+0.5);
1423  *height=(size_t) floor(scale.y*former_height/100.0+0.5);
1424  former_width=(*width);
1425  former_height=(*height);
1426  }
1427  if ((flags & AspectRatioValue) != 0)
1428  {
1429  double
1430  geometry_ratio,
1431  image_ratio;
1432 
1433  /*
1434  Geometry is a relative to image size and aspect ratio.
1435  */
1436  (void) ParseGeometry(geometry,&geometry_info);
1437  geometry_ratio=geometry_info.rho;
1438  image_ratio=(double) former_width*
1439  PerceptibleReciprocal((double) former_height);
1440  if (geometry_ratio >= image_ratio)
1441  {
1442  *width=former_width;
1443  *height=(size_t) floor((double) (PerceptibleReciprocal(
1444  geometry_ratio)*former_height*image_ratio)+0.5);
1445  }
1446  else
1447  {
1448  *width=(size_t) floor((double) (PerceptibleReciprocal(
1449  image_ratio)*former_width*geometry_ratio)+0.5);
1450  *height=former_height;
1451  }
1452  former_width=(*width);
1453  former_height=(*height);
1454  }
1455  if (((flags & AspectValue) != 0) || ((*width == former_width) &&
1456  (*height == former_height)))
1457  {
1458  if ((flags & RhoValue) == 0)
1459  *width=former_width;
1460  if ((flags & SigmaValue) == 0)
1461  *height=former_height;
1462  }
1463  else
1464  {
1465  double
1466  scale_factor;
1467 
1468  /*
1469  Respect aspect ratio of the image.
1470  */
1471  if ((former_width == 0) || (former_height == 0))
1472  scale_factor=1.0;
1473  else
1474  if (((flags & RhoValue) != 0) && (flags & SigmaValue) != 0)
1475  {
1476  scale_factor=(double) *width/(double) former_width;
1477  if ((flags & MinimumValue) == 0)
1478  {
1479  if (scale_factor > ((double) *height/(double) former_height))
1480  scale_factor=(double) *height/(double) former_height;
1481  }
1482  else
1483  if (scale_factor < ((double) *height/(double) former_height))
1484  scale_factor=(double) *height/(double) former_height;
1485  }
1486  else
1487  if ((flags & RhoValue) != 0)
1488  {
1489  scale_factor=(double) *width/(double) former_width;
1490  if (((flags & MinimumValue) != 0) &&
1491  (scale_factor < ((double) *width/(double) former_height)))
1492  scale_factor=(double) *width/(double) former_height;
1493  }
1494  else
1495  {
1496  scale_factor=(double) *height/(double) former_height;
1497  if (((flags & MinimumValue) != 0) &&
1498  (scale_factor < ((double) *height/(double) former_width)))
1499  scale_factor=(double) *height/(double) former_width;
1500  }
1501  *width=MagickMax((size_t) floor(scale_factor*former_width+0.5),1UL);
1502  *height=MagickMax((size_t) floor(scale_factor*former_height+0.5),1UL);
1503  }
1504  if ((flags & GreaterValue) != 0)
1505  {
1506  if (former_width < *width)
1507  *width=former_width;
1508  if (former_height < *height)
1509  *height=former_height;
1510  }
1511  if ((flags & LessValue) != 0)
1512  {
1513  if (former_width > *width)
1514  *width=former_width;
1515  if (former_height > *height)
1516  *height=former_height;
1517  }
1518  if ((flags & AreaValue) != 0)
1519  {
1520  double
1521  area,
1522  distance;
1523 
1524  PointInfo
1525  scale;
1526 
1527  /*
1528  Geometry is a maximum area in pixels.
1529  */
1530  (void) ParseGeometry(geometry,&geometry_info);
1531  area=geometry_info.rho+sqrt(MagickEpsilon);
1532  distance=sqrt((double) former_width*former_height);
1533  scale.x=(double) former_width*PerceptibleReciprocal(distance*
1534  PerceptibleReciprocal(sqrt(area)));
1535  scale.y=(double) former_height*PerceptibleReciprocal(distance*
1536  PerceptibleReciprocal(sqrt(area)));
1537  if ((scale.x < (double) *width) || (scale.y < (double) *height))
1538  {
1539  *width=(unsigned long) (former_width*PerceptibleReciprocal(
1540  distance*PerceptibleReciprocal(sqrt(area))));
1541  *height=(unsigned long) (former_height*PerceptibleReciprocal(
1542  distance*PerceptibleReciprocal(sqrt(area))));
1543  }
1544  former_width=(*width);
1545  former_height=(*height);
1546  }
1547  return(flags);
1548 }
1549 
1550 /*
1551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1552 % %
1553 % %
1554 % %
1555 % P a r s e P a g e G e o m e t r y %
1556 % %
1557 % %
1558 % %
1559 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1560 %
1561 % ParsePageGeometry() returns a region as defined by the geometry string with
1562 % respect to the image page (canvas) dimensions.
1563 %
1564 % WARNING: Percentage dimensions remain relative to the actual image
1565 % dimensions, and not canvas dimensions.
1566 %
1567 % The format of the ParsePageGeometry method is:
1568 %
1569 % MagickStatusType ParsePageGeometry(const Image *image,
1570 % const char *geometry,RectangeInfo *region_info,
1571 % ExceptionInfo *exception)
1572 %
1573 % A description of each parameter follows:
1574 %
1575 % o geometry: The geometry string (e.g. "100x100+10+10").
1576 %
1577 % o region_info: the region as defined by the geometry string with
1578 % respect to the image and its gravity.
1579 %
1580 % o exception: return any errors or warnings in this structure.
1581 %
1582 */
1584  const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
1585 {
1587  flags;
1588 
1589  SetGeometry(image,region_info);
1590  if (image->page.width != 0)
1591  region_info->width=image->page.width;
1592  if (image->page.height != 0)
1593  region_info->height=image->page.height;
1594  flags=ParseAbsoluteGeometry(geometry,region_info);
1595  if (flags == NoValue)
1596  {
1598  "InvalidGeometry","`%s'",geometry);
1599  return(flags);
1600  }
1601  if ((flags & PercentValue) != 0)
1602  {
1603  region_info->width=image->columns;
1604  region_info->height=image->rows;
1605  }
1606  flags=ParseMetaGeometry(geometry,&region_info->x,&region_info->y,
1607  &region_info->width,&region_info->height);
1608  if ((((flags & WidthValue) != 0) || ((flags & HeightValue) != 0)) &&
1609  (((flags & PercentValue) != 0) || ((flags & SeparatorValue) == 0)))
1610  {
1611  if ((flags & WidthValue) == 0)
1612  region_info->width=region_info->height;
1613  if ((flags & HeightValue) == 0)
1614  region_info->height=region_info->width;
1615  }
1616  return(flags);
1617 }
1618 
1619 /*
1620 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1621 % %
1622 % %
1623 % %
1624 % P a r s e R e g i o n G e o m e t r y %
1625 % %
1626 % %
1627 % %
1628 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1629 %
1630 % ParseRegionGeometry() returns a region as defined by the geometry string
1631 % with respect to the image dimensions and aspect ratio.
1632 %
1633 % This is basically a wrapper around ParseMetaGeometry. This is typically
1634 % used to parse a geometry string to work out the final integer dimensions
1635 % for image resizing.
1636 %
1637 % The format of the ParseRegionGeometry method is:
1638 %
1639 % MagickStatusType ParseRegionGeometry(const Image *image,
1640 % const char *geometry,RectangeInfo *region_info,
1641 % ExceptionInfo *exception)
1642 %
1643 % A description of each parameter follows:
1644 %
1645 % o geometry: The geometry string (e.g. "100x100+10+10").
1646 %
1647 % o region_info: the region as defined by the geometry string.
1648 %
1649 % o exception: return any errors or warnings in this structure.
1650 %
1651 */
1653  const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
1654 {
1656  flags;
1657 
1658  SetGeometry(image,region_info);
1659  flags=ParseMetaGeometry(geometry,&region_info->x,&region_info->y,
1660  &region_info->width,&region_info->height);
1661  if (flags == NoValue)
1663  "InvalidGeometry","`%s'",geometry);
1664  return(flags);
1665 }
1666 
1667 /*
1668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1669 % %
1670 % %
1671 % %
1672 % S e t G e o m e t r y %
1673 % %
1674 % %
1675 % %
1676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1677 %
1678 % SetGeometry() sets the geometry to its default values.
1679 %
1680 % The format of the SetGeometry method is:
1681 %
1682 % SetGeometry(const Image *image,RectangleInfo *geometry)
1683 %
1684 % A description of each parameter follows:
1685 %
1686 % o image: the image.
1687 %
1688 % o geometry: the geometry.
1689 %
1690 */
1691 MagickExport void SetGeometry(const Image *image,RectangleInfo *geometry)
1692 {
1693  assert(image != (Image *) NULL);
1694  assert(image->signature == MagickCoreSignature);
1695  if (image->debug != MagickFalse)
1696  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1697  assert(geometry != (RectangleInfo *) NULL);
1698  (void) memset(geometry,0,sizeof(*geometry));
1699  geometry->width=image->columns;
1700  geometry->height=image->rows;
1701 }
1702 
1703 /*
1704 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1705 % %
1706 % %
1707 % %
1708 % S e t G e o m e t r y I n f o %
1709 % %
1710 % %
1711 % %
1712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1713 %
1714 % SetGeometryInfo sets the GeometryInfo structure to its default values.
1715 %
1716 % The format of the SetGeometryInfo method is:
1717 %
1718 % SetGeometryInfo(GeometryInfo *geometry_info)
1719 %
1720 % A description of each parameter follows:
1721 %
1722 % o geometry_info: the geometry info structure.
1723 %
1724 */
1726 {
1727  assert(geometry_info != (GeometryInfo *) NULL);
1728  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1729  (void) memset(geometry_info,0,sizeof(*geometry_info));
1730 }
double psi
Definition: geometry.h:107
size_t rows
Definition: image.h:172
double rx
Definition: geometry.h:96
MagickExport size_t ConcatenateMagickString(char *magick_restrict destination, const char *magick_restrict source, const size_t length)
Definition: string.c:392
double ty
Definition: geometry.h:96
MagickExport MagickStatusType ParseAffineGeometry(const char *geometry, AffineMatrix *affine_matrix, ExceptionInfo *exception)
Definition: geometry.c:746
double rho
Definition: geometry.h:107
MagickExport MagickStatusType ParseAbsoluteGeometry(const char *geometry, RectangleInfo *region_info)
Definition: geometry.c:705
MagickExport void SetGeometryInfo(GeometryInfo *geometry_info)
Definition: geometry.c:1725
MagickExport MagickStatusType ParseMetaGeometry(const char *geometry, ssize_t *x, ssize_t *y, size_t *width, size_t *height)
Definition: geometry.c:1374
static double StringToDouble(const char *magick_restrict string, char **magick_restrict sentinal)
MagickExport ssize_t FormatLocaleString(char *magick_restrict string, const size_t length, const char *magick_restrict format,...)
Definition: locale.c:467
MagickExport size_t CopyMagickString(char *magick_restrict destination, const char *magick_restrict source, const size_t length)
Definition: string.c:719
MagickExport char * GetPageGeometry(const char *page_geometry)
Definition: geometry.c:362
#define MagickEpsilon
Definition: magick-type.h:118
double sigma
Definition: geometry.h:107
size_t width
Definition: geometry.h:131
Definition: log.h:52
Definition: image.h:151
MagickExport void GetAffineMatrix(AffineMatrix *affine_matrix)
Definition: draw.c:5865
double tx
Definition: geometry.h:96
double x
Definition: geometry.h:124
#define MagickCoreSignature
MagickExport MagickBooleanType IsGeometry(const char *geometry)
Definition: geometry.c:612
MagickBooleanType
Definition: magick-type.h:173
unsigned int MagickStatusType
Definition: magick-type.h:129
MagickExport char * AcquireString(const char *source)
Definition: string.c:94
MagickExport MagickStatusType ParsePageGeometry(const Image *image, const char *geometry, RectangleInfo *region_info, ExceptionInfo *exception)
Definition: geometry.c:1583
static double PerceptibleReciprocal(const double x)
MagickExport int LocaleNCompare(const char *p, const char *q, const size_t length)
Definition: locale.c:1527
double y
Definition: geometry.h:124
MagickExport magick_hot_spot size_t GetNextToken(const char *magick_restrict start, const char **magick_restrict end, const size_t extent, char *magick_restrict token)
Definition: token.c:174
#define MaxTextExtent
GravityType gravity
Definition: image.h:231
RectangleInfo page
Definition: image.h:212
#define MagickPageSize(name, geometry)
#define MagickPathExtent
double ry
Definition: geometry.h:96
double sx
Definition: geometry.h:96
GravityType
Definition: geometry.h:78
MagickExport MagickBooleanType ThrowMagickException(ExceptionInfo *exception, const char *module, const char *function, const size_t line, const ExceptionType severity, const char *tag, const char *format,...)
Definition: exception.c:1145
MagickExport MagickBooleanType LogMagickEvent(const LogEventType type, const char *module, const char *function, const size_t line, const char *format,...)
Definition: log.c:1660
size_t signature
Definition: image.h:354
size_t columns
Definition: image.h:172
ssize_t x
Definition: geometry.h:135
size_t height
Definition: geometry.h:131
#define MagickMax(x, y)
Definition: image-private.h:36
char filename[MagickPathExtent]
Definition: image.h:319
#define GetMagickModule()
Definition: log.h:28
double sy
Definition: geometry.h:96
double chi
Definition: geometry.h:107
MagickExport MagickStatusType GetGeometry(const char *geometry, ssize_t *x, ssize_t *y, size_t *width, size_t *height)
Definition: geometry.c:97
double xi
Definition: geometry.h:107
MagickExport MagickStatusType ParseGravityGeometry(const Image *image, const char *geometry, RectangleInfo *region_info, ExceptionInfo *exception)
Definition: geometry.c:1238
MagickExport MagickStatusType ParseGeometry(const char *geometry, GeometryInfo *geometry_info)
Definition: geometry.c:855
MagickExport void SetGeometry(const Image *image, RectangleInfo *geometry)
Definition: geometry.c:1691
MagickExport void GravityAdjustGeometry(const size_t width, const size_t height, const GravityType gravity, RectangleInfo *region)
Definition: geometry.c:533
#define MagickExport
ssize_t y
Definition: geometry.h:135
MagickExport MagickBooleanType IsSceneGeometry(const char *geometry, const MagickBooleanType pedantic)
Definition: geometry.c:653
MagickExport MagickStatusType ParseRegionGeometry(const Image *image, const char *geometry, RectangleInfo *region_info, ExceptionInfo *exception)
Definition: geometry.c:1652
MagickBooleanType debug
Definition: image.h:334