Coverage Report

Created: 2025-06-16 07:00

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