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