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