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