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