MagickCore  7.0.8
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 == ':') ||
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;
370 
371  size_t
372  extent;
373 
374  const char
375  *geometry;
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 & SigmaValue) == 0) && ((flags & XiValue) != 0) &&
1135  ((flags & PsiValue) == 0))
1136  {
1137  /*
1138  Support negative height values (e.g. 30x-20).
1139  */
1140  geometry_info->sigma=geometry_info->xi;
1141  geometry_info->xi=0.0;
1142  flags|=SigmaValue;
1143  flags&=(~XiValue);
1144  }
1145  if ((flags & PercentValue) != 0)
1146  {
1147  if (((flags & SeparatorValue) == 0) && ((flags & SigmaValue) == 0))
1148  geometry_info->sigma=geometry_info->rho;
1149  if (((flags & SeparatorValue) != 0) && ((flags & RhoValue) == 0))
1150  geometry_info->rho=geometry_info->sigma;
1151  }
1152 #if 0
1153  /* Debugging Geometry */
1154  (void) fprintf(stderr,"ParseGeometry...\n");
1155  (void) fprintf(stderr,"Flags: %c %c %s %s %s\n",
1156  (flags & RhoValue) ? 'W' : ' ',(flags & SigmaValue) ? 'H' : ' ',
1157  (flags & XiValue) ? ((flags & XiNegative) ? "-X" : "+X") : " ",
1158  (flags & PsiValue) ? ((flags & PsiNegative) ? "-Y" : "+Y") : " ",
1159  (flags & ChiValue) ? ((flags & ChiNegative) ? "-Z" : "+Z") : " ");
1160  (void) fprintf(stderr,"Geometry: %lg,%lg,%lg,%lg,%lg\n",geometry_info->rho,
1161  geometry_info->sigma,geometry_info->xi,geometry_info->psi,
1162  geometry_info->chi);
1163 #endif
1164  return(flags);
1165 }
1166 
1167 /*
1168 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1169 % %
1170 % %
1171 % %
1172 % P a r s e G r a v i t y G e o m e t r y %
1173 % %
1174 % %
1175 % %
1176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1177 %
1178 % ParseGravityGeometry() returns a region as defined by the geometry string
1179 % with respect to the given image page (canvas) dimensions and the images
1180 % gravity setting.
1181 %
1182 % This is typically used for specifing a area within a given image for
1183 % cropping images to a smaller size, chopping out rows and or columns, or
1184 % resizing and positioning overlay images.
1185 %
1186 % Percentages are relative to image size and not page size, and are set to
1187 % nearest integer (pixel) size.
1188 %
1189 % The format of the ParseGravityGeometry method is:
1190 %
1191 % MagickStatusType ParseGravityGeometry(Image *image,const char *geometry,
1192 % RectangeInfo *region_info,ExceptionInfo *exception)
1193 %
1194 % A description of each parameter follows:
1195 %
1196 % o geometry: The geometry string (e.g. "100x100+10+10").
1197 %
1198 % o region_info: the region as defined by the geometry string with respect
1199 % to the image dimensions and its gravity.
1200 %
1201 % o exception: return any errors or warnings in this structure.
1202 %
1203 */
1205  const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
1206 {
1208  flags;
1209 
1210  size_t
1211  height,
1212  width;
1213 
1214  SetGeometry(image,region_info);
1215  if (image->page.width != 0)
1216  region_info->width=image->page.width;
1217  if (image->page.height != 0)
1218  region_info->height=image->page.height;
1219  flags=ParseAbsoluteGeometry(geometry,region_info);
1220  if (flags == NoValue)
1221  {
1223  "InvalidGeometry","`%s'",geometry);
1224  return(flags);
1225  }
1226  if ((flags & PercentValue) != 0)
1227  {
1228  GeometryInfo
1229  geometry_info;
1230 
1232  status;
1233 
1234  PointInfo
1235  scale;
1236 
1237  /*
1238  Geometry is a percentage of the image size, not canvas size
1239  */
1240  if (image->gravity != UndefinedGravity)
1241  flags|=XValue | YValue;
1242  status=ParseGeometry(geometry,&geometry_info);
1243  scale.x=geometry_info.rho;
1244  if ((status & RhoValue) == 0)
1245  scale.x=100.0;
1246  scale.y=geometry_info.sigma;
1247  if ((status & SigmaValue) == 0)
1248  scale.y=scale.x;
1249  region_info->width=(size_t) floor((scale.x*image->columns/100.0)+0.5);
1250  region_info->height=(size_t) floor((scale.y*image->rows/100.0)+0.5);
1251  }
1252  if ((flags & AspectRatioValue) != 0)
1253  {
1254  double
1255  geometry_ratio,
1256  image_ratio;
1257 
1258  GeometryInfo
1259  geometry_info;
1260 
1261  /*
1262  Geometry is a relative to image size and aspect ratio.
1263  */
1264  if (image->gravity != UndefinedGravity)
1265  flags|=XValue | YValue;
1266  (void) ParseGeometry(geometry,&geometry_info);
1267  geometry_ratio=geometry_info.rho;
1268  image_ratio=(double) image->columns/image->rows;
1269  if (geometry_ratio >= image_ratio)
1270  {
1271  region_info->width=image->columns;
1272  region_info->height=(size_t) floor((double) (image->rows*image_ratio/
1273  geometry_ratio)+0.5);
1274  }
1275  else
1276  {
1277  region_info->width=(size_t) floor((double) (image->columns*
1278  geometry_ratio/image_ratio)+0.5);
1279  region_info->height=image->rows;
1280  }
1281  }
1282  /*
1283  Adjust offset according to gravity setting.
1284  */
1285  width=region_info->width;
1286  height=region_info->height;
1287  if (width == 0)
1288  region_info->width=image->page.width | image->columns;
1289  if (height == 0)
1290  region_info->height=image->page.height | image->rows;
1291  GravityAdjustGeometry(image->columns,image->rows,image->gravity,region_info);
1292  region_info->width=width;
1293  region_info->height=height;
1294  return(flags);
1295 }
1296 
1297 /*
1298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1299 % %
1300 % %
1301 % %
1302 + P a r s e M e t a G e o m e t r y %
1303 % %
1304 % %
1305 % %
1306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1307 %
1308 % ParseMetaGeometry() is similar to GetGeometry() except the returned
1309 % geometry is modified as determined by the meta characters: %, !, <, >, @,
1310 % :, and ^ in relation to image resizing.
1311 %
1312 % Final image dimensions are adjusted so as to preserve the aspect ratio as
1313 % much as possible, while generating a integer (pixel) size, and fitting the
1314 % image within the specified geometry width and height.
1315 %
1316 % Flags are interpreted...
1317 % % geometry size is given percentage of original width and height given
1318 % ! do not try to preserve aspect ratio
1319 % < only enlarge images smaller that geometry
1320 % > only shrink images larger than geometry
1321 % @ fit image to contain at most this many pixels
1322 % : width and height denotes an aspect ratio
1323 % ^ contain the given geometry given, (minimal dimensions given)
1324 %
1325 % The format of the ParseMetaGeometry method is:
1326 %
1327 % MagickStatusType ParseMetaGeometry(const char *geometry,ssize_t *x,
1328 % ssize_t *y, size_t *width,size_t *height)
1329 %
1330 % A description of each parameter follows:
1331 %
1332 % o geometry: The geometry string (e.g. "100x100+10+10").
1333 %
1334 % o x,y: The x and y offset, set according to the geometry specification.
1335 %
1336 % o width,height: The width and height of original image, modified by
1337 % the given geometry specification.
1338 %
1339 */
1340 MagickExport MagickStatusType ParseMetaGeometry(const char *geometry,ssize_t *x,
1341  ssize_t *y,size_t *width,size_t *height)
1342 {
1343  GeometryInfo
1344  geometry_info;
1345 
1347  flags;
1348 
1349  size_t
1350  former_height,
1351  former_width;
1352 
1353  /*
1354  Ensure the image geometry is valid.
1355  */
1356  assert(x != (ssize_t *) NULL);
1357  assert(y != (ssize_t *) NULL);
1358  assert(width != (size_t *) NULL);
1359  assert(height != (size_t *) NULL);
1360  if ((geometry == (char *) NULL) || (*geometry == '\0'))
1361  return(NoValue);
1362  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",geometry);
1363  /*
1364  Parse geometry using GetGeometry.
1365  */
1366  SetGeometryInfo(&geometry_info);
1367  former_width=(*width);
1368  former_height=(*height);
1369  flags=GetGeometry(geometry,x,y,width,height);
1370  if ((flags & PercentValue) != 0)
1371  {
1373  percent_flags;
1374 
1375  PointInfo
1376  scale;
1377 
1378  /*
1379  Geometry is a percentage of the image size.
1380  */
1381  percent_flags=ParseGeometry(geometry,&geometry_info);
1382  scale.x=geometry_info.rho;
1383  if ((percent_flags & RhoValue) == 0)
1384  scale.x=100.0;
1385  scale.y=geometry_info.sigma;
1386  if ((percent_flags & SigmaValue) == 0)
1387  scale.y=scale.x;
1388  *width=(size_t) MagickMax(floor(scale.x*former_width/100.0+0.5),1.0);
1389  *height=(size_t) MagickMax(floor(scale.y*former_height/100.0+0.5),1.0);
1390  former_width=(*width);
1391  former_height=(*height);
1392  }
1393  if ((flags & AspectRatioValue) != 0)
1394  {
1395  double
1396  geometry_ratio,
1397  image_ratio;
1398 
1399  GeometryInfo
1400  geometry_info;
1401 
1402  /*
1403  Geometry is a relative to image size and aspect ratio.
1404  */
1405  (void) ParseGeometry(geometry,&geometry_info);
1406  geometry_ratio=geometry_info.rho;
1407  image_ratio=(double) former_width*
1408  PerceptibleReciprocal((double) former_height);
1409  if (geometry_ratio >= image_ratio)
1410  {
1411  *width=former_width;
1412  *height=(size_t) floor((double) (former_height*image_ratio/
1413  geometry_ratio)+0.5);
1414  }
1415  else
1416  {
1417  *width=(size_t) floor((double) (former_width*geometry_ratio/
1418  image_ratio)+0.5);
1419  *height=former_height;
1420  }
1421  former_width=(*width);
1422  former_height=(*height);
1423  }
1424  if (((flags & AspectValue) != 0) || ((*width == former_width) &&
1425  (*height == former_height)))
1426  {
1427  if ((flags & RhoValue) == 0)
1428  *width=former_width;
1429  if ((flags & SigmaValue) == 0)
1430  *height=former_height;
1431  }
1432  else
1433  {
1434  double
1435  scale_factor;
1436 
1437  /*
1438  Respect aspect ratio of the image.
1439  */
1440  if ((former_width == 0) || (former_height == 0))
1441  scale_factor=1.0;
1442  else
1443  if (((flags & RhoValue) != 0) && (flags & SigmaValue) != 0)
1444  {
1445  scale_factor=(double) *width/(double) former_width;
1446  if ((flags & MinimumValue) == 0)
1447  {
1448  if (scale_factor > ((double) *height/(double) former_height))
1449  scale_factor=(double) *height/(double) former_height;
1450  }
1451  else
1452  if (scale_factor < ((double) *height/(double) former_height))
1453  scale_factor=(double) *height/(double) former_height;
1454  }
1455  else
1456  if ((flags & RhoValue) != 0)
1457  {
1458  scale_factor=(double) *width/(double) former_width;
1459  if (((flags & MinimumValue) != 0) &&
1460  (scale_factor < ((double) *width/(double) former_height)))
1461  scale_factor=(double) *width/(double) former_height;
1462  }
1463  else
1464  {
1465  scale_factor=(double) *height/(double) former_height;
1466  if (((flags & MinimumValue) != 0) &&
1467  (scale_factor < ((double) *height/(double) former_width)))
1468  scale_factor=(double) *height/(double) former_width;
1469  }
1470  *width=MagickMax((size_t) floor(scale_factor*former_width+0.5),1UL);
1471  *height=MagickMax((size_t) floor(scale_factor*former_height+0.5),1UL);
1472  }
1473  if ((flags & GreaterValue) != 0)
1474  {
1475  if (former_width < *width)
1476  *width=former_width;
1477  if (former_height < *height)
1478  *height=former_height;
1479  }
1480  if ((flags & LessValue) != 0)
1481  {
1482  if (former_width > *width)
1483  *width=former_width;
1484  if (former_height > *height)
1485  *height=former_height;
1486  }
1487  if ((flags & AreaValue) != 0)
1488  {
1489  double
1490  area,
1491  distance;
1492 
1493  PointInfo
1494  scale;
1495 
1496  /*
1497  Geometry is a maximum area in pixels.
1498  */
1499  (void) ParseGeometry(geometry,&geometry_info);
1500  area=geometry_info.rho+sqrt(MagickEpsilon);
1501  distance=sqrt((double) former_width*former_height);
1502  scale.x=(double) former_width*PerceptibleReciprocal(distance/sqrt(area));
1503  scale.y=(double) former_height*PerceptibleReciprocal(distance/sqrt(area));
1504  if ((scale.x < (double) *width) || (scale.y < (double) *height))
1505  {
1506  *width=(unsigned long) (former_width*PerceptibleReciprocal(
1507  distance/sqrt(area)));
1508  *height=(unsigned long) (former_height*PerceptibleReciprocal(
1509  distance/sqrt(area)));
1510  }
1511  former_width=(*width);
1512  former_height=(*height);
1513  }
1514  return(flags);
1515 }
1516 
1517 /*
1518 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1519 % %
1520 % %
1521 % %
1522 % P a r s e P a g e G e o m e t r y %
1523 % %
1524 % %
1525 % %
1526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1527 %
1528 % ParsePageGeometry() returns a region as defined by the geometry string with
1529 % respect to the image page (canvas) dimensions.
1530 %
1531 % WARNING: Percentage dimensions remain relative to the actual image
1532 % dimensions, and not canvas dimensions.
1533 %
1534 % The format of the ParsePageGeometry method is:
1535 %
1536 % MagickStatusType ParsePageGeometry(const Image *image,
1537 % const char *geometry,RectangeInfo *region_info,
1538 % ExceptionInfo *exception)
1539 %
1540 % A description of each parameter follows:
1541 %
1542 % o geometry: The geometry string (e.g. "100x100+10+10").
1543 %
1544 % o region_info: the region as defined by the geometry string with
1545 % respect to the image and its gravity.
1546 %
1547 % o exception: return any errors or warnings in this structure.
1548 %
1549 */
1551  const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
1552 {
1554  flags;
1555 
1556  SetGeometry(image,region_info);
1557  if (image->page.width != 0)
1558  region_info->width=image->page.width;
1559  if (image->page.height != 0)
1560  region_info->height=image->page.height;
1561  flags=ParseAbsoluteGeometry(geometry,region_info);
1562  if (flags == NoValue)
1563  {
1565  "InvalidGeometry","`%s'",geometry);
1566  return(flags);
1567  }
1568  if ((flags & PercentValue) != 0)
1569  {
1570  region_info->width=image->columns;
1571  region_info->height=image->rows;
1572  }
1573  flags=ParseMetaGeometry(geometry,&region_info->x,&region_info->y,
1574  &region_info->width,&region_info->height);
1575  if ((((flags & WidthValue) != 0) || ((flags & HeightValue) != 0)) &&
1576  (((flags & PercentValue) != 0) || ((flags & SeparatorValue) == 0)))
1577  {
1578  if ((flags & WidthValue) == 0)
1579  region_info->width=region_info->height;
1580  if ((flags & HeightValue) == 0)
1581  region_info->height=region_info->width;
1582  }
1583  return(flags);
1584 }
1585 
1586 /*
1587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1588 % %
1589 % %
1590 % %
1591 % P a r s e R e g i o n G e o m e t r y %
1592 % %
1593 % %
1594 % %
1595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1596 %
1597 % ParseRegionGeometry() returns a region as defined by the geometry string
1598 % with respect to the image dimensions and aspect ratio.
1599 %
1600 % This is basically a wrapper around ParseMetaGeometry. This is typically
1601 % used to parse a geometry string to work out the final integer dimensions
1602 % for image resizing.
1603 %
1604 % The format of the ParseRegionGeometry method is:
1605 %
1606 % MagickStatusType ParseRegionGeometry(const Image *image,
1607 % const char *geometry,RectangeInfo *region_info,
1608 % ExceptionInfo *exception)
1609 %
1610 % A description of each parameter follows:
1611 %
1612 % o geometry: The geometry string (e.g. "100x100+10+10").
1613 %
1614 % o region_info: the region as defined by the geometry string.
1615 %
1616 % o exception: return any errors or warnings in this structure.
1617 %
1618 */
1620  const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
1621 {
1623  flags;
1624 
1625  SetGeometry(image,region_info);
1626  flags=ParseMetaGeometry(geometry,&region_info->x,&region_info->y,
1627  &region_info->width,&region_info->height);
1628  if (flags == NoValue)
1630  "InvalidGeometry","`%s'",geometry);
1631  return(flags);
1632 }
1633 
1634 /*
1635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1636 % %
1637 % %
1638 % %
1639 % S e t G e o m e t r y %
1640 % %
1641 % %
1642 % %
1643 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1644 %
1645 % SetGeometry() sets the geometry to its default values.
1646 %
1647 % The format of the SetGeometry method is:
1648 %
1649 % SetGeometry(const Image *image,RectangleInfo *geometry)
1650 %
1651 % A description of each parameter follows:
1652 %
1653 % o image: the image.
1654 %
1655 % o geometry: the geometry.
1656 %
1657 */
1658 MagickExport void SetGeometry(const Image *image,RectangleInfo *geometry)
1659 {
1660  assert(image != (Image *) NULL);
1661  assert(image->signature == MagickCoreSignature);
1662  if (image->debug != MagickFalse)
1663  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1664  assert(geometry != (RectangleInfo *) NULL);
1665  (void) memset(geometry,0,sizeof(*geometry));
1666  geometry->width=image->columns;
1667  geometry->height=image->rows;
1668 }
1669 
1670 /*
1671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1672 % %
1673 % %
1674 % %
1675 % S e t G e o m e t r y I n f o %
1676 % %
1677 % %
1678 % %
1679 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1680 %
1681 % SetGeometryInfo sets the GeometryInfo structure to its default values.
1682 %
1683 % The format of the SetGeometryInfo method is:
1684 %
1685 % SetGeometryInfo(GeometryInfo *geometry_info)
1686 %
1687 % A description of each parameter follows:
1688 %
1689 % o geometry_info: the geometry info structure.
1690 %
1691 */
1693 {
1694  assert(geometry_info != (GeometryInfo *) NULL);
1695  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1696  (void) memset(geometry_info,0,sizeof(*geometry_info));
1697 }
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:1692
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:1340
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:504
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:5681
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:156
unsigned int MagickStatusType
Definition: magick-type.h:119
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:1550
static double PerceptibleReciprocal(const double x)
MagickExport int LocaleNCompare(const char *p, const char *q, const size_t length)
Definition: locale.c:1540
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:1064
MagickExport MagickBooleanType LogMagickEvent(const LogEventType type, const char *module, const char *function, const size_t line, const char *format,...)
Definition: log.c:1398
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:1204
MagickExport MagickStatusType ParseGeometry(const char *geometry, GeometryInfo *geometry_info)
Definition: geometry.c:853
MagickExport void SetGeometry(const Image *image, RectangleInfo *geometry)
Definition: geometry.c:1658
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:1619
MagickBooleanType debug
Definition: image.h:334