MagickCore  7.0.3
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-2019 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[11];
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  GetNextToken(p,&p,MagickPathExtent,token);
768  if (*token == ',')
769  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  case ')':
946  {
947  (void) CopyMagickString(p,p+1,MagickPathExtent);
948  break;
949  }
950  case 'x':
951  case 'X':
952  {
953  flags|=SeparatorValue;
954  p++;
955  break;
956  }
957  case '-':
958  case '+':
959  case ',':
960  case '0':
961  case '1':
962  case '2':
963  case '3':
964  case '4':
965  case '5':
966  case '6':
967  case '7':
968  case '8':
969  case '9':
970  case '/':
971  case 215:
972  case 'e':
973  case 'E':
974  {
975  p++;
976  break;
977  }
978  case '.':
979  {
980  p++;
981  flags|=DecimalValue;
982  break;
983  }
984  case ':':
985  {
986  p++;
987  flags|=AspectRatioValue;
988  break;
989  }
990  default:
991  return(NoValue);
992  }
993  }
994  /*
995  Parse rho, sigma, xi, psi, and optionally chi.
996  */
997  p=pedantic_geometry;
998  if (*p == '\0')
999  return(flags);
1000  q=p;
1001  value=StringToDouble(p,&q);
1002  if (LocaleNCompare(p,"0x",2) == 0)
1003  (void) strtol(p,&q,10);
1004  c=(int) ((unsigned char) *q);
1005  if ((c == 215) || (*q == 'x') || (*q == 'X') || (*q == ':') ||
1006  (*q == ',') || (*q == '/') || (*q =='\0'))
1007  {
1008  /*
1009  Parse rho.
1010  */
1011  q=p;
1012  if (LocaleNCompare(p,"0x",2) == 0)
1013  value=(double) strtol(p,&p,10);
1014  else
1015  value=StringToDouble(p,&p);
1016  if (p != q)
1017  {
1018  flags|=RhoValue;
1019  geometry_info->rho=value;
1020  }
1021  }
1022  q=p;
1023  c=(int) ((unsigned char) *p);
1024  if ((c == 215) || (*p == 'x') || (*p == 'X') || (*p == ':') || (*p == ',') ||
1025  (*p == '/'))
1026  {
1027  /*
1028  Parse sigma.
1029  */
1030  p++;
1031  while (isspace((int) ((unsigned char) *p)) != 0)
1032  p++;
1033  c=(int) ((unsigned char) *q);
1034  if (((c != 215) && (*q != 'x') && (*q != 'X') && (*q != ':')) ||
1035  ((*p != '+') && (*p != '-')))
1036  {
1037  q=p;
1038  value=StringToDouble(p,&p);
1039  if (p != q)
1040  {
1041  flags|=SigmaValue;
1042  geometry_info->sigma=value;
1043  }
1044  }
1045  }
1046  while (isspace((int) ((unsigned char) *p)) != 0)
1047  p++;
1048  if ((*p == '+') || (*p == '-') || (*p == ',') || (*p == '/') || (*p == ':'))
1049  {
1050  /*
1051  Parse xi value.
1052  */
1053  if ((*p == ',') || (*p == '/') || (*p == ':') )
1054  p++;
1055  while ((*p == '+') || (*p == '-'))
1056  {
1057  if (*p == '-')
1058  flags^=XiNegative; /* negate sign */
1059  p++;
1060  }
1061  q=p;
1062  value=StringToDouble(p,&p);
1063  if (p != q)
1064  {
1065  flags|=XiValue;
1066  if ((flags & XiNegative) != 0)
1067  value=(-value);
1068  geometry_info->xi=value;
1069  }
1070  while (isspace((int) ((unsigned char) *p)) != 0)
1071  p++;
1072  if ((*p == '+') || (*p == '-') || (*p == ',') || (*p == '/') ||
1073  (*p == ':'))
1074  {
1075  /*
1076  Parse psi value.
1077  */
1078  if ((*p == ',') || (*p == '/') || (*p == ':'))
1079  p++;
1080  while ((*p == '+') || (*p == '-'))
1081  {
1082  if (*p == '-')
1083  flags^=PsiNegative; /* negate sign */
1084  p++;
1085  }
1086  q=p;
1087  value=StringToDouble(p,&p);
1088  if (p != q)
1089  {
1090  flags|=PsiValue;
1091  if ((flags & PsiNegative) != 0)
1092  value=(-value);
1093  geometry_info->psi=value;
1094  }
1095  }
1096  while (isspace((int) ((unsigned char) *p)) != 0)
1097  p++;
1098  if ((*p == '+') || (*p == '-') || (*p == ',') || (*p == '/') ||
1099  (*p == ':'))
1100  {
1101  /*
1102  Parse chi value.
1103  */
1104  if ((*p == ',') || (*p == '/') || (*p == ':'))
1105  p++;
1106  while ((*p == '+') || (*p == '-'))
1107  {
1108  if (*p == '-')
1109  flags^=ChiNegative; /* negate sign */
1110  p++;
1111  }
1112  q=p;
1113  value=StringToDouble(p,&p);
1114  if (p != q)
1115  {
1116  flags|=ChiValue;
1117  if ((flags & ChiNegative) != 0)
1118  value=(-value);
1119  geometry_info->chi=value;
1120  }
1121  }
1122  }
1123  if (strchr(pedantic_geometry,':') != (char *) NULL)
1124  {
1125  /*
1126  Normalize sampling factor (e.g. 4:2:2 => 2x1).
1127  */
1128  if ((flags & SigmaValue) != 0)
1129  geometry_info->rho*=PerceptibleReciprocal(geometry_info->sigma);
1130  geometry_info->sigma=1.0;
1131  if (((flags & XiValue) != 0) && (geometry_info->xi == 0.0))
1132  geometry_info->sigma=2.0;
1133  }
1134  if (((flags & RhoValue) != 0) && ((flags & SigmaValue) == 0) &&
1135  ((flags & XiValue) != 0) && ((flags & XiNegative) != 0))
1136  {
1137  if ((flags & PsiValue) == 0)
1138  {
1139  /*
1140  Support negative height values (e.g. 30x-20).
1141  */
1142  geometry_info->sigma=geometry_info->xi;
1143  geometry_info->xi=0.0;
1144  flags|=SigmaValue;
1145  flags&=(~XiValue);
1146  }
1147  else
1148  if ((flags & ChiValue) == 0)
1149  {
1150  /*
1151  Support negative height values (e.g. 30x-20+10).
1152  */
1153  geometry_info->sigma=geometry_info->xi;
1154  geometry_info->xi=geometry_info->psi;
1155  flags|=SigmaValue;
1156  flags|=XiValue;
1157  flags&=(~PsiValue);
1158  }
1159  else
1160  {
1161  /*
1162  Support negative height values (e.g. 30x-20+10+10).
1163  */
1164  geometry_info->sigma=geometry_info->xi;
1165  geometry_info->xi=geometry_info->psi;
1166  geometry_info->psi=geometry_info->chi;
1167  flags|=SigmaValue;
1168  flags|=XiValue;
1169  flags|=PsiValue;
1170  flags&=(~ChiValue);
1171  }
1172  }
1173  if ((flags & PercentValue) != 0)
1174  {
1175  if (((flags & SeparatorValue) == 0) && ((flags & SigmaValue) == 0))
1176  geometry_info->sigma=geometry_info->rho;
1177  if (((flags & SeparatorValue) != 0) && ((flags & RhoValue) == 0))
1178  geometry_info->rho=geometry_info->sigma;
1179  }
1180 #if 0
1181  /* Debugging Geometry */
1182  (void) fprintf(stderr,"ParseGeometry...\n");
1183  (void) fprintf(stderr,"Flags: %c %c %s %s %s\n",
1184  (flags & RhoValue) ? 'W' : ' ',(flags & SigmaValue) ? 'H' : ' ',
1185  (flags & XiValue) ? ((flags & XiNegative) ? "-X" : "+X") : " ",
1186  (flags & PsiValue) ? ((flags & PsiNegative) ? "-Y" : "+Y") : " ",
1187  (flags & ChiValue) ? ((flags & ChiNegative) ? "-Z" : "+Z") : " ");
1188  (void) fprintf(stderr,"Geometry: %lg,%lg,%lg,%lg,%lg\n",geometry_info->rho,
1189  geometry_info->sigma,geometry_info->xi,geometry_info->psi,
1190  geometry_info->chi);
1191 #endif
1192  return(flags);
1193 }
1194 
1195 /*
1196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1197 % %
1198 % %
1199 % %
1200 % P a r s e G r a v i t y G e o m e t r y %
1201 % %
1202 % %
1203 % %
1204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1205 %
1206 % ParseGravityGeometry() returns a region as defined by the geometry string
1207 % with respect to the given image page (canvas) dimensions and the images
1208 % gravity setting.
1209 %
1210 % This is typically used for specifing a area within a given image for
1211 % cropping images to a smaller size, chopping out rows and or columns, or
1212 % resizing and positioning overlay images.
1213 %
1214 % Percentages are relative to image size and not page size, and are set to
1215 % nearest integer (pixel) size.
1216 %
1217 % The format of the ParseGravityGeometry method is:
1218 %
1219 % MagickStatusType ParseGravityGeometry(Image *image,const char *geometry,
1220 % RectangeInfo *region_info,ExceptionInfo *exception)
1221 %
1222 % A description of each parameter follows:
1223 %
1224 % o geometry: The geometry string (e.g. "100x100+10+10").
1225 %
1226 % o region_info: the region as defined by the geometry string with respect
1227 % to the image dimensions and its gravity.
1228 %
1229 % o exception: return any errors or warnings in this structure.
1230 %
1231 */
1233  const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
1234 {
1236  flags;
1237 
1238  size_t
1239  height,
1240  width;
1241 
1242  SetGeometry(image,region_info);
1243  if (image->page.width != 0)
1244  region_info->width=image->page.width;
1245  if (image->page.height != 0)
1246  region_info->height=image->page.height;
1247  flags=ParseAbsoluteGeometry(geometry,region_info);
1248  if (flags == NoValue)
1249  {
1251  "InvalidGeometry","`%s'",geometry);
1252  return(flags);
1253  }
1254  if ((flags & PercentValue) != 0)
1255  {
1256  GeometryInfo
1257  geometry_info;
1258 
1260  status;
1261 
1262  PointInfo
1263  scale;
1264 
1265  /*
1266  Geometry is a percentage of the image size, not canvas size
1267  */
1268  if (image->gravity != UndefinedGravity)
1269  flags|=XValue | YValue;
1270  status=ParseGeometry(geometry,&geometry_info);
1271  scale.x=geometry_info.rho;
1272  if ((status & RhoValue) == 0)
1273  scale.x=100.0;
1274  scale.y=geometry_info.sigma;
1275  if ((status & SigmaValue) == 0)
1276  scale.y=scale.x;
1277  region_info->width=(size_t) floor((scale.x*image->columns/100.0)+0.5);
1278  region_info->height=(size_t) floor((scale.y*image->rows/100.0)+0.5);
1279  }
1280  if ((flags & AspectRatioValue) != 0)
1281  {
1282  double
1283  geometry_ratio,
1284  image_ratio;
1285 
1286  GeometryInfo
1287  geometry_info;
1288 
1289  /*
1290  Geometry is a relative to image size and aspect ratio.
1291  */
1292  if (image->gravity != UndefinedGravity)
1293  flags|=XValue | YValue;
1294  (void) ParseGeometry(geometry,&geometry_info);
1295  geometry_ratio=geometry_info.rho;
1296  image_ratio=(double) image->columns/image->rows;
1297  if (geometry_ratio >= image_ratio)
1298  {
1299  region_info->width=image->columns;
1300  region_info->height=(size_t) floor((double) (image->rows*image_ratio/
1301  geometry_ratio)+0.5);
1302  }
1303  else
1304  {
1305  region_info->width=(size_t) floor((double) (image->columns*
1306  geometry_ratio/image_ratio)+0.5);
1307  region_info->height=image->rows;
1308  }
1309  }
1310  /*
1311  Adjust offset according to gravity setting.
1312  */
1313  width=region_info->width;
1314  height=region_info->height;
1315  if (width == 0)
1316  region_info->width=image->page.width | image->columns;
1317  if (height == 0)
1318  region_info->height=image->page.height | image->rows;
1319  GravityAdjustGeometry(image->columns,image->rows,image->gravity,region_info);
1320  region_info->width=width;
1321  region_info->height=height;
1322  return(flags);
1323 }
1324 
1325 /*
1326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1327 % %
1328 % %
1329 % %
1330 + P a r s e M e t a G e o m e t r y %
1331 % %
1332 % %
1333 % %
1334 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1335 %
1336 % ParseMetaGeometry() is similar to GetGeometry() except the returned
1337 % geometry is modified as determined by the meta characters: %, !, <, >, @,
1338 % :, and ^ in relation to image resizing.
1339 %
1340 % Final image dimensions are adjusted so as to preserve the aspect ratio as
1341 % much as possible, while generating a integer (pixel) size, and fitting the
1342 % image within the specified geometry width and height.
1343 %
1344 % Flags are interpreted...
1345 % % geometry size is given percentage of original width and height given
1346 % ! do not try to preserve aspect ratio
1347 % < only enlarge images smaller that geometry
1348 % > only shrink images larger than geometry
1349 % @ fit image to contain at most this many pixels
1350 % : width and height denotes an aspect ratio
1351 % ^ contain the given geometry given, (minimal dimensions given)
1352 %
1353 % The format of the ParseMetaGeometry method is:
1354 %
1355 % MagickStatusType ParseMetaGeometry(const char *geometry,ssize_t *x,
1356 % ssize_t *y, size_t *width,size_t *height)
1357 %
1358 % A description of each parameter follows:
1359 %
1360 % o geometry: The geometry string (e.g. "100x100+10+10").
1361 %
1362 % o x,y: The x and y offset, set according to the geometry specification.
1363 %
1364 % o width,height: The width and height of original image, modified by
1365 % the given geometry specification.
1366 %
1367 */
1368 MagickExport MagickStatusType ParseMetaGeometry(const char *geometry,ssize_t *x,
1369  ssize_t *y,size_t *width,size_t *height)
1370 {
1371  GeometryInfo
1372  geometry_info;
1373 
1375  flags;
1376 
1377  size_t
1378  former_height,
1379  former_width;
1380 
1381  /*
1382  Ensure the image geometry is valid.
1383  */
1384  assert(x != (ssize_t *) NULL);
1385  assert(y != (ssize_t *) NULL);
1386  assert(width != (size_t *) NULL);
1387  assert(height != (size_t *) NULL);
1388  if ((geometry == (char *) NULL) || (*geometry == '\0'))
1389  return(NoValue);
1390  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",geometry);
1391  /*
1392  Parse geometry using GetGeometry.
1393  */
1394  SetGeometryInfo(&geometry_info);
1395  former_width=(*width);
1396  former_height=(*height);
1397  flags=GetGeometry(geometry,x,y,width,height);
1398  if ((flags & PercentValue) != 0)
1399  {
1401  percent_flags;
1402 
1403  PointInfo
1404  scale;
1405 
1406  /*
1407  Geometry is a percentage of the image size.
1408  */
1409  percent_flags=ParseGeometry(geometry,&geometry_info);
1410  scale.x=geometry_info.rho;
1411  if ((percent_flags & RhoValue) == 0)
1412  scale.x=100.0;
1413  scale.y=geometry_info.sigma;
1414  if ((percent_flags & SigmaValue) == 0)
1415  scale.y=scale.x;
1416  *width=(size_t) MagickMax(floor(scale.x*former_width/100.0+0.5),1.0);
1417  *height=(size_t) MagickMax(floor(scale.y*former_height/100.0+0.5),1.0);
1418  former_width=(*width);
1419  former_height=(*height);
1420  }
1421  if ((flags & AspectRatioValue) != 0)
1422  {
1423  double
1424  geometry_ratio,
1425  image_ratio;
1426 
1427  GeometryInfo
1428  geometry_info;
1429 
1430  /*
1431  Geometry is a relative to image size and aspect ratio.
1432  */
1433  (void) ParseGeometry(geometry,&geometry_info);
1434  geometry_ratio=geometry_info.rho;
1435  image_ratio=(double) former_width*
1436  PerceptibleReciprocal((double) former_height);
1437  if (geometry_ratio >= image_ratio)
1438  {
1439  *width=former_width;
1440  *height=(size_t) floor((double) (former_height*image_ratio/
1441  geometry_ratio)+0.5);
1442  }
1443  else
1444  {
1445  *width=(size_t) floor((double) (former_width*geometry_ratio/
1446  image_ratio)+0.5);
1447  *height=former_height;
1448  }
1449  former_width=(*width);
1450  former_height=(*height);
1451  }
1452  if (((flags & AspectValue) != 0) || ((*width == former_width) &&
1453  (*height == former_height)))
1454  {
1455  if ((flags & RhoValue) == 0)
1456  *width=former_width;
1457  if ((flags & SigmaValue) == 0)
1458  *height=former_height;
1459  }
1460  else
1461  {
1462  double
1463  scale_factor;
1464 
1465  /*
1466  Respect aspect ratio of the image.
1467  */
1468  if ((former_width == 0) || (former_height == 0))
1469  scale_factor=1.0;
1470  else
1471  if (((flags & RhoValue) != 0) && (flags & SigmaValue) != 0)
1472  {
1473  scale_factor=(double) *width/(double) former_width;
1474  if ((flags & MinimumValue) == 0)
1475  {
1476  if (scale_factor > ((double) *height/(double) former_height))
1477  scale_factor=(double) *height/(double) former_height;
1478  }
1479  else
1480  if (scale_factor < ((double) *height/(double) former_height))
1481  scale_factor=(double) *height/(double) former_height;
1482  }
1483  else
1484  if ((flags & RhoValue) != 0)
1485  {
1486  scale_factor=(double) *width/(double) former_width;
1487  if (((flags & MinimumValue) != 0) &&
1488  (scale_factor < ((double) *width/(double) former_height)))
1489  scale_factor=(double) *width/(double) former_height;
1490  }
1491  else
1492  {
1493  scale_factor=(double) *height/(double) former_height;
1494  if (((flags & MinimumValue) != 0) &&
1495  (scale_factor < ((double) *height/(double) former_width)))
1496  scale_factor=(double) *height/(double) former_width;
1497  }
1498  *width=MagickMax((size_t) floor(scale_factor*former_width+0.5),1UL);
1499  *height=MagickMax((size_t) floor(scale_factor*former_height+0.5),1UL);
1500  }
1501  if ((flags & GreaterValue) != 0)
1502  {
1503  if (former_width < *width)
1504  *width=former_width;
1505  if (former_height < *height)
1506  *height=former_height;
1507  }
1508  if ((flags & LessValue) != 0)
1509  {
1510  if (former_width > *width)
1511  *width=former_width;
1512  if (former_height > *height)
1513  *height=former_height;
1514  }
1515  if ((flags & AreaValue) != 0)
1516  {
1517  double
1518  area,
1519  distance;
1520 
1521  PointInfo
1522  scale;
1523 
1524  /*
1525  Geometry is a maximum area in pixels.
1526  */
1527  (void) ParseGeometry(geometry,&geometry_info);
1528  area=geometry_info.rho+sqrt(MagickEpsilon);
1529  distance=sqrt((double) former_width*former_height);
1530  scale.x=(double) former_width*PerceptibleReciprocal(distance/sqrt(area));
1531  scale.y=(double) former_height*PerceptibleReciprocal(distance/sqrt(area));
1532  if ((scale.x < (double) *width) || (scale.y < (double) *height))
1533  {
1534  *width=(unsigned long) (former_width*PerceptibleReciprocal(
1535  distance/sqrt(area)));
1536  *height=(unsigned long) (former_height*PerceptibleReciprocal(
1537  distance/sqrt(area)));
1538  }
1539  former_width=(*width);
1540  former_height=(*height);
1541  }
1542  return(flags);
1543 }
1544 
1545 /*
1546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1547 % %
1548 % %
1549 % %
1550 % P a r s e P a g e G e o m e t r y %
1551 % %
1552 % %
1553 % %
1554 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1555 %
1556 % ParsePageGeometry() returns a region as defined by the geometry string with
1557 % respect to the image page (canvas) dimensions.
1558 %
1559 % WARNING: Percentage dimensions remain relative to the actual image
1560 % dimensions, and not canvas dimensions.
1561 %
1562 % The format of the ParsePageGeometry method is:
1563 %
1564 % MagickStatusType ParsePageGeometry(const Image *image,
1565 % const char *geometry,RectangeInfo *region_info,
1566 % ExceptionInfo *exception)
1567 %
1568 % A description of each parameter follows:
1569 %
1570 % o geometry: The geometry string (e.g. "100x100+10+10").
1571 %
1572 % o region_info: the region as defined by the geometry string with
1573 % respect to the image and its gravity.
1574 %
1575 % o exception: return any errors or warnings in this structure.
1576 %
1577 */
1579  const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
1580 {
1582  flags;
1583 
1584  SetGeometry(image,region_info);
1585  if (image->page.width != 0)
1586  region_info->width=image->page.width;
1587  if (image->page.height != 0)
1588  region_info->height=image->page.height;
1589  flags=ParseAbsoluteGeometry(geometry,region_info);
1590  if (flags == NoValue)
1591  {
1593  "InvalidGeometry","`%s'",geometry);
1594  return(flags);
1595  }
1596  if ((flags & PercentValue) != 0)
1597  {
1598  region_info->width=image->columns;
1599  region_info->height=image->rows;
1600  }
1601  flags=ParseMetaGeometry(geometry,&region_info->x,&region_info->y,
1602  &region_info->width,&region_info->height);
1603  if ((((flags & WidthValue) != 0) || ((flags & HeightValue) != 0)) &&
1604  (((flags & PercentValue) != 0) || ((flags & SeparatorValue) == 0)))
1605  {
1606  if ((flags & WidthValue) == 0)
1607  region_info->width=region_info->height;
1608  if ((flags & HeightValue) == 0)
1609  region_info->height=region_info->width;
1610  }
1611  return(flags);
1612 }
1613 
1614 /*
1615 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1616 % %
1617 % %
1618 % %
1619 % P a r s e R e g i o n G e o m e t r y %
1620 % %
1621 % %
1622 % %
1623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1624 %
1625 % ParseRegionGeometry() returns a region as defined by the geometry string
1626 % with respect to the image dimensions and aspect ratio.
1627 %
1628 % This is basically a wrapper around ParseMetaGeometry. This is typically
1629 % used to parse a geometry string to work out the final integer dimensions
1630 % for image resizing.
1631 %
1632 % The format of the ParseRegionGeometry method is:
1633 %
1634 % MagickStatusType ParseRegionGeometry(const Image *image,
1635 % const char *geometry,RectangeInfo *region_info,
1636 % ExceptionInfo *exception)
1637 %
1638 % A description of each parameter follows:
1639 %
1640 % o geometry: The geometry string (e.g. "100x100+10+10").
1641 %
1642 % o region_info: the region as defined by the geometry string.
1643 %
1644 % o exception: return any errors or warnings in this structure.
1645 %
1646 */
1648  const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
1649 {
1651  flags;
1652 
1653  SetGeometry(image,region_info);
1654  flags=ParseMetaGeometry(geometry,&region_info->x,&region_info->y,
1655  &region_info->width,&region_info->height);
1656  if (flags == NoValue)
1658  "InvalidGeometry","`%s'",geometry);
1659  return(flags);
1660 }
1661 
1662 /*
1663 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1664 % %
1665 % %
1666 % %
1667 % S e t G e o m e t r y %
1668 % %
1669 % %
1670 % %
1671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1672 %
1673 % SetGeometry() sets the geometry to its default values.
1674 %
1675 % The format of the SetGeometry method is:
1676 %
1677 % SetGeometry(const Image *image,RectangleInfo *geometry)
1678 %
1679 % A description of each parameter follows:
1680 %
1681 % o image: the image.
1682 %
1683 % o geometry: the geometry.
1684 %
1685 */
1686 MagickExport void SetGeometry(const Image *image,RectangleInfo *geometry)
1687 {
1688  assert(image != (Image *) NULL);
1689  assert(image->signature == MagickCoreSignature);
1690  if (image->debug != MagickFalse)
1691  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1692  assert(geometry != (RectangleInfo *) NULL);
1693  (void) memset(geometry,0,sizeof(*geometry));
1694  geometry->width=image->columns;
1695  geometry->height=image->rows;
1696 }
1697 
1698 /*
1699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1700 % %
1701 % %
1702 % %
1703 % S e t G e o m e t r y I n f o %
1704 % %
1705 % %
1706 % %
1707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1708 %
1709 % SetGeometryInfo sets the GeometryInfo structure to its default values.
1710 %
1711 % The format of the SetGeometryInfo method is:
1712 %
1713 % SetGeometryInfo(GeometryInfo *geometry_info)
1714 %
1715 % A description of each parameter follows:
1716 %
1717 % o geometry_info: the geometry info structure.
1718 %
1719 */
1721 {
1722  assert(geometry_info != (GeometryInfo *) NULL);
1723  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1724  (void) memset(geometry_info,0,sizeof(*geometry_info));
1725 }
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: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:1720
MagickExport size_t ConcatenateMagickString(char *destination, const char *source, const size_t length)
Definition: string.c:426
MagickExport MagickStatusType ParseMetaGeometry(const char *geometry, ssize_t *x, ssize_t *y, size_t *width, size_t *height)
Definition: geometry.c:1368
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 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:5743
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:1578
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
#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:1403
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:755
#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:172
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:1232
MagickExport MagickStatusType ParseGeometry(const char *geometry, GeometryInfo *geometry_info)
Definition: geometry.c:853
MagickExport void SetGeometry(const Image *image, RectangleInfo *geometry)
Definition: geometry.c:1686
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:1647
MagickBooleanType debug
Definition: image.h:334