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