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