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