Coverage Report

Created: 2026-02-14 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/MagickCore/geometry.c
Line
Count
Source
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/license/                                         %
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
314k
{
205
314k
  char
206
314k
    *p,
207
314k
    pedantic_geometry[MagickPathExtent],
208
314k
    *q;
209
210
314k
  double
211
314k
    value;
212
213
314k
  int
214
314k
    c;
215
216
314k
  MagickStatusType
217
314k
    flags;
218
219
  /*
220
    Remove whitespace and meta characters from geometry specification.
221
  */
222
314k
  flags=NoValue;
223
314k
  if ((geometry == (char *) NULL) || (*geometry == '\0'))
224
1.94k
    return(flags);
225
312k
  if (strlen(geometry) >= (MagickPathExtent-1))
226
15
    return(flags);
227
312k
  (void) CopyMagickString(pedantic_geometry,geometry,MagickPathExtent);
228
4.30M
  for (p=pedantic_geometry; *p != '\0'; )
229
3.99M
  {
230
3.99M
    if (isspace((int) ((unsigned char) *p)) != 0)
231
65.6k
      {
232
65.6k
        (void) CopyMagickString(p,p+1,MagickPathExtent);
233
65.6k
        continue;
234
65.6k
      }
235
3.92M
    c=(int) *p;
236
3.92M
    switch (c)
237
3.92M
    {
238
59.2k
      case '%':
239
59.2k
      {
240
59.2k
        flags|=PercentValue;
241
59.2k
        (void) CopyMagickString(p,p+1,MagickPathExtent);
242
59.2k
        break;
243
0
      }
244
61.9k
      case '!':
245
61.9k
      {
246
61.9k
        flags|=AspectValue;
247
61.9k
        (void) CopyMagickString(p,p+1,MagickPathExtent);
248
61.9k
        break;
249
0
      }
250
27.4k
      case '<':
251
27.4k
      {
252
27.4k
        flags|=LessValue;
253
27.4k
        (void) CopyMagickString(p,p+1,MagickPathExtent);
254
27.4k
        break;
255
0
      }
256
57.4k
      case '>':
257
57.4k
      {
258
57.4k
        flags|=GreaterValue;
259
57.4k
        (void) CopyMagickString(p,p+1,MagickPathExtent);
260
57.4k
        break;
261
0
      }
262
29.4k
      case '#':
263
29.4k
      {
264
29.4k
        flags|=MaximumValue;
265
29.4k
        (void) CopyMagickString(p,p+1,MagickPathExtent);
266
29.4k
        break;
267
0
      }
268
13.0k
      case '^':
269
13.0k
      {
270
13.0k
        flags|=MinimumValue;
271
13.0k
        (void) CopyMagickString(p,p+1,MagickPathExtent);
272
13.0k
        break;
273
0
      }
274
24.7k
      case '@':
275
24.7k
      {
276
24.7k
        flags|=AreaValue;
277
24.7k
        (void) CopyMagickString(p,p+1,MagickPathExtent);
278
24.7k
        break;
279
0
      }
280
32.0k
      case '(':
281
61.9k
      case ')':
282
61.9k
      {
283
61.9k
        (void) CopyMagickString(p,p+1,MagickPathExtent);
284
61.9k
        break;
285
32.0k
      }
286
233k
      case 'x':
287
258k
      case 'X':
288
258k
      {
289
258k
        flags|=SeparatorValue;
290
258k
        p++;
291
258k
        break;
292
233k
      }
293
134k
      case '-':
294
164k
      case ',':
295
493k
      case '+':
296
1.45M
      case '0':
297
1.78M
      case '1':
298
2.12M
      case '2':
299
2.26M
      case '3':
300
2.46M
      case '4':
301
2.58M
      case '5':
302
2.74M
      case '6':
303
2.91M
      case '7':
304
3.03M
      case '8':
305
3.16M
      case '9':
306
3.16M
      case 215:
307
3.19M
      case 'e':
308
3.22M
      case 'E':
309
3.22M
      {
310
3.22M
        p++;
311
3.22M
        break;
312
3.19M
      }
313
70.6k
      case '.':
314
70.6k
      {
315
70.6k
        p++;
316
70.6k
        flags|=DecimalValue;
317
70.6k
        break;
318
3.19M
      }
319
36.8k
      case ':':
320
36.8k
      {
321
36.8k
        p++;
322
36.8k
        flags|=AspectRatioValue;
323
36.8k
        break;
324
3.19M
      }
325
7.27k
      default:
326
7.27k
        return(flags);
327
3.92M
    }
328
3.92M
  }
329
  /*
330
    Parse width, height, x, and y.
331
  */
332
305k
  p=pedantic_geometry;
333
305k
  if (*p == '\0')
334
2.49k
    return(flags);
335
302k
  q=p;
336
302k
  value=StringToDouble(p,&q);
337
302k
  (void) value;
338
302k
  if (LocaleNCompare(p,"0x",2) == 0)
339
54.1k
    value=(double) strtol(p,&q,10);
340
302k
  if ((*p != '+') && (*p != '-'))
341
271k
    {
342
271k
      c=(int) ((unsigned char) *q);
343
271k
      if ((c == 215) || (*q == 'x') || (*q == 'X') || (*q == ':') ||
344
19.7k
          (*q == '\0'))
345
269k
        {
346
          /*
347
            Parse width.
348
          */
349
269k
          q=p;
350
269k
          if (width != (size_t *) NULL)
351
269k
            {
352
269k
              if (LocaleNCompare(p,"0x",2) == 0)
353
54.1k
                *width=(size_t) strtol(p,&p,10);
354
215k
              else
355
215k
                *width=CastDoubleToSizeT(StringToDouble(p,&p)+0.5);
356
269k
            }
357
269k
          if (p != q)
358
252k
            flags|=WidthValue;
359
269k
        }
360
271k
    }
361
302k
  if ((*p != '+') && (*p != '-'))
362
271k
    {
363
271k
      c=(int) ((unsigned char) *p);
364
271k
      if ((c == 215) || (*p == 'x') || (*p == 'X') || (*p == ':'))
365
252k
        {
366
252k
          p++;
367
252k
          if ((*p != '+') && (*p != '-'))
368
234k
            {
369
              /*
370
                Parse height.
371
              */
372
234k
              q=p;
373
234k
              if (height != (size_t *) NULL)
374
234k
                *height=CastDoubleToSizeT(StringToDouble(p,&p)+0.5);
375
234k
              if (p != q)
376
226k
                flags|=HeightValue;
377
234k
            }
378
252k
        }
379
271k
    }
380
302k
  if ((*p == '+') || (*p == '-'))
381
191k
    {
382
      /*
383
        Parse x value.
384
      */
385
410k
      while ((*p == '+') || (*p == '-'))
386
219k
      {
387
219k
        if (*p == '-')
388
54.5k
          flags^=XNegative;  /* negate sign */
389
219k
        p++;
390
219k
      }
391
191k
      q=p;
392
191k
      if (x != (ssize_t *) NULL)
393
191k
        *x=CastDoubleToSsizeT(StringToDouble(p,&p));
394
191k
      if (p != q)
395
178k
        {
396
178k
          flags|=XValue;
397
178k
          if (((flags & XNegative) != 0) && (x != (ssize_t *) NULL))
398
27.7k
            *x=CastDoubleToSsizeT(-1.0**x);
399
178k
        }
400
191k
    }
401
302k
  if ((*p == '+') || (*p == '-'))
402
165k
    {
403
      /*
404
        Parse y value.
405
      */
406
351k
      while ((*p == '+') || (*p == '-'))
407
185k
      {
408
185k
        if (*p == '-')
409
35.9k
          flags^=YNegative;  /* negate sign */
410
185k
        p++;
411
185k
      }
412
165k
      q=p;
413
165k
      if (y != (ssize_t *) NULL)
414
165k
        *y=CastDoubleToSsizeT(StringToDouble(p,&p));
415
165k
      if (p != q)
416
159k
        {
417
159k
          flags|=YValue;
418
159k
          if (((flags & YNegative) != 0) && (y != (ssize_t *) NULL))
419
22.0k
            *y=CastDoubleToSsizeT(-1.0**y);
420
159k
        }
421
165k
    }
422
302k
  if ((flags & PercentValue) != 0)
423
33.6k
    {
424
33.6k
      if (((flags & SeparatorValue) == 0) && ((flags & HeightValue) == 0))
425
18.5k
        {
426
18.5k
          if ((height != (size_t *) NULL) && (width != (size_t *) NULL))
427
18.5k
            *height=(*width);
428
18.5k
          flags|=HeightValue;
429
18.5k
        }
430
33.6k
      if (((flags & SeparatorValue) != 0) && ((flags & WidthValue) == 0) &&
431
4.78k
          (height != (size_t *) NULL) && (width != (size_t *) NULL))
432
4.78k
        *width=(*height);
433
33.6k
    }
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
302k
  return(flags);
446
305k
}
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
58.5k
{
475
58.5k
  char
476
58.5k
    page[MagickPathExtent];
477
478
58.5k
  ssize_t
479
58.5k
    i;
480
481
58.5k
  assert(page_geometry != (char *) NULL);
482
58.5k
  if (IsEventLogging() != MagickFalse)
483
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",page_geometry);
484
58.5k
  (void) CopyMagickString(page,page_geometry,MagickPathExtent);
485
3.80M
  for (i=0; *Pagesizes[i].name != '\0'; i++)
486
3.75M
  {
487
3.75M
    int
488
3.75M
      status;
489
490
3.75M
    if (Pagesizes[i].extent == 0)
491
0
      break;  /* sentinel */
492
3.75M
    status=LocaleNCompare(Pagesizes[i].name,page_geometry,Pagesizes[i].extent);
493
3.75M
    if (status == 0)
494
17.5k
      {
495
17.5k
        MagickStatusType
496
17.5k
          flags;
497
498
17.5k
        RectangleInfo
499
17.5k
          geometry;
500
501
        /*
502
          Replace mnemonic with the equivalent size in dots-per-inch.
503
        */
504
17.5k
        (void) FormatLocaleString(page,MagickPathExtent,"%s%.80s",
505
17.5k
          Pagesizes[i].geometry,page_geometry+Pagesizes[i].extent);
506
17.5k
        flags=GetGeometry(page,&geometry.x,&geometry.y,&geometry.width,
507
17.5k
          &geometry.height);
508
17.5k
        if ((flags & GreaterValue) == 0)
509
13.2k
          (void) ConcatenateMagickString(page,">",MagickPathExtent);
510
17.5k
        break;
511
17.5k
      }
512
3.75M
  }
513
58.5k
  return(AcquireString(page));
514
58.5k
}
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
13.8k
{
550
13.8k
  if (region->height == 0)
551
1.80k
    region->height=height;
552
13.8k
  if (region->width == 0)
553
1.80k
    region->width=width;
554
13.8k
  switch (gravity)
555
13.8k
  {
556
0
    case NorthEastGravity:
557
901
    case EastGravity:
558
901
    case SouthEastGravity:
559
901
    {
560
901
      region->x=CastDoubleToSsizeT((double) width-region->width-region->x);
561
901
      break;
562
901
    }
563
1.38k
    case NorthGravity:
564
2.28k
    case SouthGravity:
565
6.41k
    case CenterGravity:
566
6.41k
    {
567
6.41k
      region->x=CastDoubleToSsizeT((double) width/2.0-region->width/2.0+
568
6.41k
        region->x);
569
6.41k
      break;
570
2.28k
    }
571
5.67k
    case ForgetGravity:
572
5.67k
    case NorthWestGravity:
573
6.57k
    case WestGravity:
574
6.57k
    case SouthWestGravity:
575
6.57k
    default:
576
6.57k
      break;
577
13.8k
  }
578
13.8k
  switch (gravity)
579
13.8k
  {
580
0
    case SouthWestGravity:
581
901
    case SouthGravity:
582
901
    case SouthEastGravity:
583
901
    {
584
901
      region->y=CastDoubleToSsizeT((double) height-region->height-region->y);
585
901
      break;
586
901
    }
587
901
    case EastGravity:
588
1.80k
    case WestGravity:
589
5.93k
    case CenterGravity:
590
5.93k
    {
591
5.93k
      region->y=CastDoubleToSsizeT((double) height/2.0-region->height/2.0+
592
5.93k
        region->y);
593
5.93k
      break;
594
1.80k
    }
595
5.67k
    case ForgetGravity:
596
5.67k
    case NorthWestGravity:
597
7.05k
    case NorthGravity:
598
7.05k
    case NorthEastGravity:
599
7.05k
    default:
600
7.05k
      break;
601
13.8k
  }
602
13.8k
  return;
603
13.8k
}
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
194k
{
630
194k
  GeometryInfo
631
194k
    geometry_info;
632
633
194k
  MagickStatusType
634
194k
    flags;
635
636
194k
  if (geometry == (const char *) NULL)
637
0
    return(MagickFalse);
638
194k
  flags=ParseGeometry(geometry,&geometry_info);
639
194k
  return(flags != NoValue ? MagickTrue : MagickFalse);
640
194k
}
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
552k
{
672
552k
  char
673
552k
    *p;
674
675
552k
  double
676
552k
    value;
677
678
552k
  if (geometry == (const char *) NULL)
679
342k
    return(MagickFalse);
680
209k
  p=(char *) geometry;
681
209k
  value=StringToDouble(geometry,&p);
682
209k
  if (IsNaN(value) != 0)
683
345
    return(MagickFalse);
684
209k
  if (value > (double) MAGICK_SSIZE_MAX)
685
5.65k
    return(MagickFalse);
686
203k
  if (value < (double) MAGICK_SSIZE_MIN)
687
422
    return(MagickFalse);
688
203k
  if (p == geometry)
689
111k
    return(MagickFalse);
690
91.7k
  if (strspn(geometry,"0123456789-, ") != strlen(geometry))
691
75.5k
    return(MagickFalse);
692
16.2k
  if ((pedantic != MagickFalse) && (strchr(geometry,',') != (char *) NULL))
693
0
    return(MagickFalse);
694
16.2k
  return(MagickTrue);
695
16.2k
}
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
257k
{
775
257k
  MagickStatusType
776
257k
    flags;
777
778
257k
  flags=GetGeometry(geometry,&region_info->x,&region_info->y,
779
257k
    &region_info->width,&region_info->height);
780
257k
  return(flags);
781
257k
}
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
401k
{
925
401k
  char
926
401k
    *p,
927
401k
    pedantic_geometry[MagickPathExtent],
928
401k
    *q;
929
930
401k
  double
931
401k
    value;
932
933
401k
  GeometryInfo
934
401k
    coordinate;
935
936
401k
  int
937
401k
    c;
938
939
401k
  MagickStatusType
940
401k
    flags;
941
942
  /*
943
    Remove whitespaces meta characters from geometry specification.
944
  */
945
401k
  assert(geometry_info != (GeometryInfo *) NULL);
946
401k
  (void) memset(geometry_info,0,sizeof(*geometry_info));
947
401k
  flags=NoValue;
948
401k
  if ((geometry == (char *) NULL) || (*geometry == '\0'))
949
7.94k
    return(flags);
950
393k
  if (strlen(geometry) >= (MagickPathExtent-1))
951
211
    return(flags);
952
393k
  c=MagickSscanf(geometry,"%lf%*[ ,]%lf%*[ ,]%lf%*[ ,]%lf",&coordinate.rho,
953
393k
    &coordinate.sigma,&coordinate.xi,&coordinate.psi);
954
393k
  if (c == 4)
955
2.37k
    {
956
      /*
957
        Special case: coordinate (e.g. 0,0 255,255).
958
      */
959
2.37k
      geometry_info->rho=coordinate.rho;
960
2.37k
      geometry_info->sigma=coordinate.sigma;
961
2.37k
      geometry_info->xi=coordinate.xi;
962
2.37k
      geometry_info->psi=coordinate.psi;
963
2.37k
      flags|=RhoValue | SigmaValue | XiValue | PsiValue;
964
2.37k
      return(flags);
965
2.37k
    }
966
390k
  (void) CopyMagickString(pedantic_geometry,geometry,MagickPathExtent);
967
5.24M
  for (p=pedantic_geometry; *p != '\0'; )
968
4.91M
  {
969
4.91M
    c=(int) ((unsigned char) *p);
970
4.91M
    if (isspace((int) ((unsigned char) c)) != 0)
971
191k
      {
972
191k
        (void) CopyMagickString(p,p+1,MagickPathExtent);
973
191k
        continue;
974
191k
      }
975
4.72M
    switch (c)
976
4.72M
    {
977
109k
      case '%':
978
109k
      {
979
109k
        flags|=PercentValue;
980
109k
        (void) CopyMagickString(p,p+1,MagickPathExtent);
981
109k
        break;
982
0
      }
983
44.7k
      case '!':
984
44.7k
      {
985
44.7k
        flags|=AspectValue;
986
44.7k
        (void) CopyMagickString(p,p+1,MagickPathExtent);
987
44.7k
        break;
988
0
      }
989
39.6k
      case '<':
990
39.6k
      {
991
39.6k
        flags|=LessValue;
992
39.6k
        (void) CopyMagickString(p,p+1,MagickPathExtent);
993
39.6k
        break;
994
0
      }
995
41.0k
      case '>':
996
41.0k
      {
997
41.0k
        flags|=GreaterValue;
998
41.0k
        (void) CopyMagickString(p,p+1,MagickPathExtent);
999
41.0k
        break;
1000
0
      }
1001
61.6k
      case '#':
1002
61.6k
      {
1003
61.6k
        flags|=MaximumValue;
1004
61.6k
        (void) CopyMagickString(p,p+1,MagickPathExtent);
1005
61.6k
        break;
1006
0
      }
1007
20.6k
      case '^':
1008
20.6k
      {
1009
20.6k
        flags|=MinimumValue;
1010
20.6k
        (void) CopyMagickString(p,p+1,MagickPathExtent);
1011
20.6k
        break;
1012
0
      }
1013
39.6k
      case '@':
1014
39.6k
      {
1015
39.6k
        flags|=AreaValue;
1016
39.6k
        (void) CopyMagickString(p,p+1,MagickPathExtent);
1017
39.6k
        break;
1018
0
      }
1019
77.8k
      case '(':
1020
77.8k
      {
1021
77.8k
        if (*(p+1) == ')')
1022
1.32k
          return(flags);
1023
76.5k
        (void) CopyMagickString(p,p+1,MagickPathExtent);
1024
76.5k
        break;
1025
77.8k
      }
1026
38.2k
      case ')':
1027
38.2k
      {
1028
38.2k
        (void) CopyMagickString(p,p+1,MagickPathExtent);
1029
38.2k
        break;
1030
77.8k
      }
1031
182k
      case 'x':
1032
224k
      case 'X':
1033
224k
      {
1034
224k
        flags|=SeparatorValue;
1035
224k
        p++;
1036
224k
        break;
1037
182k
      }
1038
259k
      case '-':
1039
422k
      case '+':
1040
560k
      case ',':
1041
1.51M
      case '0':
1042
1.83M
      case '1':
1043
2.12M
      case '2':
1044
2.35M
      case '3':
1045
2.54M
      case '4':
1046
2.72M
      case '5':
1047
2.88M
      case '6':
1048
3.12M
      case '7':
1049
3.28M
      case '8':
1050
3.38M
      case '9':
1051
3.47M
      case '/':
1052
3.47M
      case 215:
1053
3.52M
      case 'e':
1054
3.57M
      case 'E':
1055
3.57M
      {
1056
3.57M
        p++;
1057
3.57M
        break;
1058
3.52M
      }
1059
265k
      case '.':
1060
265k
      {
1061
265k
        p++;
1062
265k
        flags|=DecimalValue;
1063
265k
        break;
1064
3.52M
      }
1065
131k
      case ':':
1066
131k
      {
1067
131k
        p++;
1068
131k
        flags|=AspectRatioValue;
1069
131k
        break;
1070
3.52M
      }
1071
62.7k
      default:
1072
62.7k
        return(NoValue);
1073
4.72M
    }
1074
4.72M
  }
1075
  /*
1076
    Parse rho, sigma, xi, psi, and optionally chi.
1077
  */
1078
326k
  p=pedantic_geometry;
1079
326k
  if (*p == '\0')
1080
5.42k
    return(flags);
1081
321k
  q=p;
1082
321k
  value=StringToDouble(p,&q);
1083
321k
  if (LocaleNCompare(p,"0x",2) == 0)
1084
6.07k
    (void) strtol(p,&q,10);
1085
321k
  c=(int) ((unsigned char) *q);
1086
321k
  if ((c == 215) || (*q == 'x') || (*q == 'X') || (*q == ':') ||
1087
99.6k
      (*q == ',') || (*q == '/') || (*q =='\0'))
1088
279k
    {
1089
      /*
1090
        Parse rho.
1091
      */
1092
279k
      q=p;
1093
279k
      if (LocaleNCompare(p,"0x",2) == 0)
1094
6.07k
        value=(double) strtol(p,&p,10);
1095
273k
      else
1096
273k
        value=StringToDouble(p,&p);
1097
279k
      if (p != q)
1098
222k
        {
1099
222k
          flags|=RhoValue;
1100
222k
          geometry_info->rho=value;
1101
222k
        }
1102
279k
    }
1103
321k
  q=p;
1104
321k
  c=(int) ((unsigned char) *p);
1105
321k
  if ((c == 215) || (*p == 'x') || (*p == 'X') || (*p == ':') || (*p == ',') ||
1106
86.9k
      (*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
221k
          ((*p != '+') && (*p != '-')))
1117
213k
        {
1118
213k
          q=p;
1119
213k
          value=StringToDouble(p,&p);
1120
213k
          if (p != q)
1121
166k
            {
1122
166k
              flags|=SigmaValue;
1123
166k
              geometry_info->sigma=value;
1124
166k
            }
1125
213k
        }
1126
242k
    }
1127
321k
  while (isspace((int) ((unsigned char) *p)) != 0)
1128
0
    p++;
1129
321k
  if ((*p == '+') || (*p == '-') || (*p == ',') || (*p == '/') || (*p == ':'))
1130
127k
    {
1131
      /*
1132
        Parse xi value.
1133
      */
1134
127k
      if ((*p == ',') || (*p == '/') || (*p == ':') )
1135
35.7k
        p++;
1136
271k
      while ((*p == '+') || (*p == '-'))
1137
144k
      {
1138
144k
        if (*p == '-')
1139
79.5k
          flags^=XiNegative;  /* negate sign */
1140
144k
        p++;
1141
144k
      }
1142
127k
      q=p;
1143
127k
      value=StringToDouble(p,&p);
1144
127k
      if (p != q)
1145
92.7k
        {
1146
92.7k
          flags|=XiValue;
1147
92.7k
          if ((flags & XiNegative) != 0)
1148
36.7k
            value=(-value);
1149
92.7k
          geometry_info->xi=value;
1150
92.7k
        }
1151
127k
      while (isspace((int) ((unsigned char) *p)) != 0)
1152
0
        p++;
1153
127k
      if ((*p == '+') || (*p == '-') || (*p == ',') || (*p == '/') ||
1154
68.1k
          (*p == ':'))
1155
67.5k
        {
1156
          /*
1157
            Parse psi value.
1158
          */
1159
67.5k
          if ((*p == ',') || (*p == '/') || (*p == ':'))
1160
26.5k
            p++;
1161
151k
          while ((*p == '+') || (*p == '-'))
1162
83.7k
          {
1163
83.7k
            if (*p == '-')
1164
43.7k
              flags^=PsiNegative;  /* negate sign */
1165
83.7k
            p++;
1166
83.7k
          }
1167
67.5k
          q=p;
1168
67.5k
          value=StringToDouble(p,&p);
1169
67.5k
          if (p != q)
1170
47.1k
            {
1171
47.1k
              flags|=PsiValue;
1172
47.1k
              if ((flags & PsiNegative) != 0)
1173
13.5k
                value=(-value);
1174
47.1k
              geometry_info->psi=value;
1175
47.1k
            }
1176
67.5k
      }
1177
127k
      while (isspace((int) ((unsigned char) *p)) != 0)
1178
0
        p++;
1179
127k
      if ((*p == '+') || (*p == '-') || (*p == ',') || (*p == '/') ||
1180
105k
          (*p == ':'))
1181
25.8k
        {
1182
          /*
1183
            Parse chi value.
1184
          */
1185
25.8k
          if ((*p == ',') || (*p == '/') || (*p == ':'))
1186
14.1k
            p++;
1187
63.3k
          while ((*p == '+') || (*p == '-'))
1188
37.5k
          {
1189
37.5k
            if (*p == '-')
1190
23.9k
              flags^=ChiNegative;  /* negate sign */
1191
37.5k
            p++;
1192
37.5k
          }
1193
25.8k
          q=p;
1194
25.8k
          value=StringToDouble(p,&p);
1195
25.8k
          if (p != q)
1196
13.7k
            {
1197
13.7k
              flags|=ChiValue;
1198
13.7k
              if ((flags & ChiNegative) != 0)
1199
6.91k
                value=(-value);
1200
13.7k
              geometry_info->chi=value;
1201
13.7k
            }
1202
25.8k
        }
1203
127k
    }
1204
321k
  if (strchr(pedantic_geometry,':') != (char *) NULL)
1205
86.3k
    {
1206
      /*
1207
        Normalize sampling factor (e.g. 4:2:2 => 2x1).
1208
      */
1209
86.3k
      if ((flags & SigmaValue) != 0)
1210
30.4k
        geometry_info->rho*=MagickSafeReciprocal(geometry_info->sigma);
1211
86.3k
      geometry_info->sigma=1.0;
1212
86.3k
      if (((flags & XiValue) != 0) && (geometry_info->xi == 0.0))
1213
6.85k
        geometry_info->sigma=2.0;
1214
86.3k
    }
1215
321k
  if (((flags & RhoValue) != 0) && ((flags & SigmaValue) == 0) &&
1216
90.3k
      ((flags & XiValue) != 0) && ((flags & XiNegative) != 0))
1217
19.9k
    {
1218
19.9k
      if ((flags & PsiValue) == 0)
1219
9.30k
        {
1220
          /*
1221
            Support negative height values (e.g. 30x-20).
1222
          */
1223
9.30k
          geometry_info->sigma=geometry_info->xi;
1224
9.30k
          geometry_info->xi=0.0;
1225
9.30k
          flags|=SigmaValue;
1226
9.30k
          flags&=(unsigned int) (~XiValue);
1227
9.30k
        }
1228
10.6k
      else
1229
10.6k
        if ((flags & ChiValue) == 0)
1230
8.18k
          {
1231
            /*
1232
              Support negative height values (e.g. 30x-20+10).
1233
            */
1234
8.18k
            geometry_info->sigma=geometry_info->xi;
1235
8.18k
            geometry_info->xi=geometry_info->psi;
1236
8.18k
            flags|=SigmaValue;
1237
8.18k
            flags|=XiValue;
1238
8.18k
            flags&=(unsigned int) (~PsiValue);
1239
8.18k
          }
1240
2.43k
        else
1241
2.43k
          {
1242
            /*
1243
              Support negative height values (e.g. 30x-20+10+10).
1244
            */
1245
2.43k
            geometry_info->sigma=geometry_info->xi;
1246
2.43k
            geometry_info->xi=geometry_info->psi;
1247
2.43k
            geometry_info->psi=geometry_info->chi;
1248
2.43k
            flags|=SigmaValue;
1249
2.43k
            flags|=XiValue;
1250
2.43k
            flags|=PsiValue;
1251
2.43k
            flags&=(unsigned int) (~ChiValue);
1252
2.43k
          }
1253
19.9k
    }
1254
321k
  if ((flags & PercentValue) != 0)
1255
65.1k
    {
1256
65.1k
      if (((flags & SeparatorValue) == 0) && ((flags & SigmaValue) == 0))
1257
22.0k
        geometry_info->sigma=geometry_info->rho;
1258
65.1k
      if (((flags & SeparatorValue) != 0) && ((flags & RhoValue) == 0))
1259
20.0k
        geometry_info->rho=geometry_info->sigma;
1260
65.1k
    }
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
321k
  return(flags);
1274
326k
}
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
10.2k
{
1316
10.2k
  MagickStatusType
1317
10.2k
    flags;
1318
1319
10.2k
  size_t
1320
10.2k
    height,
1321
10.2k
    width;
1322
1323
10.2k
  if (IsEventLogging() != MagickFalse)
1324
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",geometry);
1325
10.2k
  if ((geometry == (char *) NULL) || (*geometry == '\0'))
1326
0
    return(NoValue);
1327
10.2k
  SetGeometry(image,region_info);
1328
10.2k
  if (image->page.width != 0)
1329
0
    region_info->width=image->page.width;
1330
10.2k
  if (image->page.height != 0)
1331
0
    region_info->height=image->page.height;
1332
10.2k
  flags=ParseAbsoluteGeometry(geometry,region_info);
1333
10.2k
  if (flags == NoValue)
1334
0
    {
1335
0
      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1336
0
        "InvalidGeometry","`%s'",geometry);
1337
0
      return(flags);
1338
0
    }
1339
10.2k
  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
10.2k
  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
10.2k
  width=region_info->width;
1405
10.2k
  height=region_info->height;
1406
10.2k
  if (width == 0)
1407
0
    region_info->width=image->page.width | image->columns;
1408
10.2k
  if (height == 0)
1409
0
    region_info->height=image->page.height | image->rows;
1410
10.2k
  GravityAdjustGeometry(image->columns,image->rows,image->gravity,region_info);
1411
10.2k
  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
10.2k
  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
10.2k
  region_info->width=width;
1426
10.2k
  region_info->height=height;
1427
10.2k
  return(flags);
1428
10.2k
}
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
37.9k
{
1476
37.9k
  GeometryInfo
1477
37.9k
    geometry_info;
1478
1479
37.9k
  MagickStatusType
1480
37.9k
    flags;
1481
1482
37.9k
  size_t
1483
37.9k
    stasis_height,
1484
37.9k
    stasis_width;
1485
1486
  /*
1487
    Ensure the image geometry is valid.
1488
  */
1489
37.9k
  assert(x != (ssize_t *) NULL);
1490
37.9k
  assert(y != (ssize_t *) NULL);
1491
37.9k
  assert(width != (size_t *) NULL);
1492
37.9k
  assert(height != (size_t *) NULL);
1493
37.9k
  if (IsEventLogging() != MagickFalse)
1494
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",geometry);
1495
37.9k
  if ((geometry == (char *) NULL) || (*geometry == '\0'))
1496
0
    return(NoValue);
1497
  /*
1498
    Parse geometry using GetGeometry.
1499
  */
1500
37.9k
  stasis_width=(*width);
1501
37.9k
  stasis_height=(*height);
1502
37.9k
  SetGeometryInfo(&geometry_info);
1503
37.9k
  flags=GetGeometry(geometry,x,y,width,height);
1504
37.9k
  if ((flags & PercentValue) != 0)
1505
2.39k
    {
1506
2.39k
      MagickStatusType
1507
2.39k
        percent_flags;
1508
1509
2.39k
      PointInfo
1510
2.39k
        scale;
1511
1512
      /*
1513
        Geometry is a percentage of the image size.
1514
      */
1515
2.39k
      percent_flags=ParseGeometry(geometry,&geometry_info);
1516
2.39k
      scale.x=geometry_info.rho;
1517
2.39k
      if ((percent_flags & RhoValue) == 0)
1518
682
        scale.x=100.0;
1519
2.39k
      scale.y=geometry_info.sigma;
1520
2.39k
      if ((percent_flags & SigmaValue) == 0)
1521
1.81k
        scale.y=scale.x;
1522
2.39k
      *width=CastDoubleToSizeT(scale.x*stasis_width/100.0+0.5);
1523
2.39k
      *height=CastDoubleToSizeT(scale.y*stasis_height/100.0+0.5);
1524
2.39k
      stasis_width=(*width);
1525
2.39k
      stasis_height=(*height);
1526
2.39k
    }
1527
37.9k
  if ((flags & AspectRatioValue) != 0)
1528
1.49k
    {
1529
1.49k
      double
1530
1.49k
        geometry_ratio,
1531
1.49k
        image_ratio;
1532
1533
      /*
1534
        Geometry is a relative to image size and aspect ratio.
1535
      */
1536
1.49k
      (void) ParseGeometry(geometry,&geometry_info);
1537
1.49k
      geometry_ratio=geometry_info.rho;
1538
1.49k
      image_ratio=(double) stasis_width*MagickSafeReciprocal((double)
1539
1.49k
        stasis_height);
1540
1.49k
      if (geometry_ratio >= image_ratio)
1541
853
        {
1542
853
          *width=stasis_width;
1543
853
          *height=CastDoubleToSizeT((double) (MagickSafeReciprocal(
1544
853
            geometry_ratio)*stasis_height*image_ratio)+0.5);
1545
853
        }
1546
638
      else
1547
638
        {
1548
638
          *width=CastDoubleToSizeT(MagickSafeReciprocal(image_ratio)*
1549
638
            stasis_width*geometry_ratio+0.5);
1550
638
          *height=stasis_height;
1551
638
        }
1552
1.49k
      stasis_width=(*width);
1553
1.49k
      stasis_height=(*height);
1554
1.49k
    }
1555
37.9k
  if (((flags & AspectValue) != 0) || ((*width == stasis_width) &&
1556
20.0k
      (*height == stasis_height)))
1557
25.5k
    {
1558
25.5k
      if ((flags & RhoValue) == 0)
1559
13.5k
        *width=stasis_width;
1560
25.5k
      if ((flags & SigmaValue) == 0)
1561
13.0k
        *height=stasis_height;
1562
25.5k
    }
1563
12.3k
  else
1564
12.3k
    {
1565
12.3k
      double
1566
12.3k
        scale_factor;
1567
1568
      /*
1569
        Respect aspect ratio of the image.
1570
      */
1571
12.3k
      if ((stasis_width == 0) || (stasis_height == 0))
1572
0
        scale_factor=1.0;
1573
12.3k
      else
1574
12.3k
        if (((flags & RhoValue) != 0) && (flags & SigmaValue) != 0)
1575
8.69k
          {
1576
8.69k
            scale_factor=(double) *width/(double) stasis_width;
1577
8.69k
            if ((flags & MinimumValue) == 0)
1578
8.66k
              {
1579
8.66k
                if (scale_factor > ((double) *height/(double) stasis_height))
1580
444
                  scale_factor=(double) *height/(double) stasis_height;
1581
8.66k
              }
1582
37
            else
1583
37
              if (scale_factor < ((double) *height/(double) stasis_height))
1584
27
                scale_factor=(double) *height/(double) stasis_height;
1585
8.69k
          }
1586
3.69k
        else
1587
3.69k
          if ((flags & RhoValue) != 0)
1588
3.41k
            {
1589
3.41k
              scale_factor=(double) *width/(double) stasis_width;
1590
3.41k
              if (((flags & MinimumValue) != 0) &&
1591
66
                  (scale_factor < ((double) *width/(double) stasis_height)))
1592
9
                scale_factor=(double) *width/(double) stasis_height;
1593
3.41k
            }
1594
278
          else
1595
278
            {
1596
278
              scale_factor=(double) *height/(double) stasis_height;
1597
278
              if (((flags & MinimumValue) != 0) &&
1598
8
                  (scale_factor < ((double) *height/(double) stasis_width)))
1599
0
                scale_factor=(double) *height/(double) stasis_width;
1600
278
            }
1601
12.3k
      *width=CastDoubleToSizeT(MagickMax(floor(scale_factor*stasis_width+0.5),
1602
12.3k
        1.0));
1603
12.3k
      *height=CastDoubleToSizeT(MagickMax(floor(scale_factor*stasis_height+0.5),
1604
12.3k
        1.0));
1605
12.3k
    }
1606
37.9k
  if ((flags & GreaterValue) != 0)
1607
9.12k
    {
1608
9.12k
      if (stasis_width < *width)
1609
7.50k
        *width=stasis_width;
1610
9.12k
      if (stasis_height < *height)
1611
7.22k
        *height=stasis_height;
1612
9.12k
    }
1613
37.9k
  if ((flags & LessValue) != 0)
1614
1.16k
    {
1615
1.16k
      if (stasis_width > *width)
1616
35
        *width=stasis_width;
1617
1.16k
      if (stasis_height > *height)
1618
49
        *height=stasis_height;
1619
1.16k
    }
1620
37.9k
  if ((flags & AreaValue) != 0)
1621
957
    {
1622
957
      double
1623
957
        area,
1624
957
        distance;
1625
1626
957
      PointInfo
1627
957
        scale;
1628
1629
      /*
1630
        Geometry is a maximum area in pixels.
1631
      */
1632
957
      (void) ParseGeometry(geometry,&geometry_info);
1633
957
      area=geometry_info.rho+sqrt(MagickEpsilon);
1634
957
      distance=sqrt((double) stasis_width*stasis_height);
1635
957
      scale.x=(double) stasis_width*MagickSafeReciprocal(distance*
1636
957
        MagickSafeReciprocal(sqrt(area)));
1637
957
      scale.y=(double) stasis_height*MagickSafeReciprocal(distance*
1638
957
        MagickSafeReciprocal(sqrt(area)));
1639
957
      if ((scale.x < (double) *width) || (scale.y < (double) *height))
1640
423
        {
1641
423
          *width=CastDoubleToSizeT((double) stasis_width*MagickSafeReciprocal(
1642
423
            distance*MagickSafeReciprocal(sqrt(area)))+0.5);
1643
423
          *height=CastDoubleToSizeT((double) stasis_height*MagickSafeReciprocal(
1644
423
            distance*MagickSafeReciprocal(sqrt(area)))+0.5);
1645
423
        }
1646
957
    }
1647
37.9k
  return(flags);
1648
37.9k
}
1649

1650
/*
1651
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1652
%                                                                             %
1653
%                                                                             %
1654
%                                                                             %
1655
%   P a r s e P a g e G e o m e t r y                                         %
1656
%                                                                             %
1657
%                                                                             %
1658
%                                                                             %
1659
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1660
%
1661
%  ParsePageGeometry() returns a region as defined by the geometry string with
1662
%  respect to the image page (canvas) dimensions.
1663
%
1664
%  WARNING: Percentage dimensions remain relative to the actual image
1665
%  dimensions, and not canvas dimensions.
1666
%
1667
%  The format of the ParsePageGeometry method is:
1668
%
1669
%      MagickStatusType ParsePageGeometry(const Image *image,
1670
%        const char *geometry,RectangleInfo *region_info,
1671
%        ExceptionInfo *exception)
1672
%
1673
%  A description of each parameter follows:
1674
%
1675
%    o geometry:  The geometry string (e.g. "100x100+10+10").
1676
%
1677
%    o region_info: the region as defined by the geometry string with
1678
%      respect to the image and its gravity.
1679
%
1680
%    o exception: return any errors or warnings in this structure.
1681
%
1682
*/
1683
MagickExport MagickStatusType ParsePageGeometry(const Image *image,
1684
  const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
1685
15.9k
{
1686
15.9k
  MagickStatusType
1687
15.9k
    flags;
1688
1689
15.9k
  SetGeometry(image,region_info);
1690
15.9k
  if (image->page.width != 0)
1691
0
    region_info->width=image->page.width;
1692
15.9k
  if (image->page.height != 0)
1693
0
    region_info->height=image->page.height;
1694
15.9k
  flags=ParseAbsoluteGeometry(geometry,region_info);
1695
15.9k
  if (flags == NoValue)
1696
0
    {
1697
0
      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1698
0
        "InvalidGeometry","`%s'",geometry);
1699
0
      return(flags);
1700
0
    }
1701
15.9k
  if ((flags & PercentValue) != 0)
1702
0
    {
1703
0
      region_info->width=image->columns;
1704
0
      region_info->height=image->rows;
1705
0
    }
1706
15.9k
  flags=ParseMetaGeometry(geometry,&region_info->x,&region_info->y,
1707
15.9k
    &region_info->width,&region_info->height);
1708
15.9k
  if ((((flags & WidthValue) != 0) || ((flags & HeightValue) != 0)) &&
1709
4.13k
      (((flags & PercentValue) != 0) || ((flags & SeparatorValue) == 0)))
1710
0
    {
1711
0
      if ((flags & WidthValue) == 0)
1712
0
        region_info->width=region_info->height;
1713
0
      if ((flags & HeightValue) == 0)
1714
0
        region_info->height=region_info->width;
1715
0
    }
1716
15.9k
  return(flags);
1717
15.9k
}
1718

1719
/*
1720
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1721
%                                                                             %
1722
%                                                                             %
1723
%                                                                             %
1724
%   P a r s e R e g i o n G e o m e t r y                                     %
1725
%                                                                             %
1726
%                                                                             %
1727
%                                                                             %
1728
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1729
%
1730
%  ParseRegionGeometry() returns a region as defined by the geometry string
1731
%  with respect to the image dimensions and aspect ratio.
1732
%
1733
%  This is basically a wrapper around ParseMetaGeometry.  This is typically
1734
%  used to parse a geometry string to work out the final integer dimensions
1735
%  for image resizing.
1736
%
1737
%  The format of the ParseRegionGeometry method is:
1738
%
1739
%      MagickStatusType ParseRegionGeometry(const Image *image,
1740
%        const char *geometry,RectangleInfo *region_info,
1741
%        ExceptionInfo *exception)
1742
%
1743
%  A description of each parameter follows:
1744
%
1745
%    o geometry:  The geometry string (e.g. "100x100+10+10").
1746
%
1747
%    o region_info: the region as defined by the geometry string.
1748
%
1749
%    o exception: return any errors or warnings in this structure.
1750
%
1751
*/
1752
MagickExport MagickStatusType ParseRegionGeometry(const Image *image,
1753
  const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
1754
17.8k
{
1755
17.8k
  MagickStatusType
1756
17.8k
    flags;
1757
1758
17.8k
  SetGeometry(image,region_info);
1759
17.8k
  flags=ParseMetaGeometry(geometry,&region_info->x,&region_info->y,
1760
17.8k
    &region_info->width,&region_info->height);
1761
17.8k
  if (flags == NoValue)
1762
0
    (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1763
0
      "InvalidGeometry","`%s'",geometry);
1764
17.8k
  return(flags);
1765
17.8k
}
1766

1767
/*
1768
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1769
%                                                                             %
1770
%                                                                             %
1771
%                                                                             %
1772
%   S e t G e o m e t r y                                                     %
1773
%                                                                             %
1774
%                                                                             %
1775
%                                                                             %
1776
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1777
%
1778
%  SetGeometry() sets the geometry to its default values.
1779
%
1780
%  The format of the SetGeometry method is:
1781
%
1782
%      SetGeometry(const Image *image,RectangleInfo *geometry)
1783
%
1784
%  A description of each parameter follows:
1785
%
1786
%    o image: the image.
1787
%
1788
%    o geometry: the geometry.
1789
%
1790
*/
1791
MagickExport void SetGeometry(const Image *image,RectangleInfo *geometry)
1792
88.6k
{
1793
88.6k
  assert(image != (Image *) NULL);
1794
88.6k
  assert(image->signature == MagickCoreSignature);
1795
88.6k
  if (IsEventLogging() != MagickFalse)
1796
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1797
88.6k
  assert(geometry != (RectangleInfo *) NULL);
1798
88.6k
  (void) memset(geometry,0,sizeof(*geometry));
1799
88.6k
  geometry->width=image->columns;
1800
88.6k
  geometry->height=image->rows;
1801
88.6k
}
1802

1803
/*
1804
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1805
%                                                                             %
1806
%                                                                             %
1807
%                                                                             %
1808
%   S e t G e o m e t r y I n f o                                             %
1809
%                                                                             %
1810
%                                                                             %
1811
%                                                                             %
1812
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1813
%
1814
%  SetGeometryInfo sets the GeometryInfo structure to its default values.
1815
%
1816
%  The format of the SetGeometryInfo method is:
1817
%
1818
%      SetGeometryInfo(GeometryInfo *geometry_info)
1819
%
1820
%  A description of each parameter follows:
1821
%
1822
%    o geometry_info: the geometry info structure.
1823
%
1824
*/
1825
MagickExport void SetGeometryInfo(GeometryInfo *geometry_info)
1826
177k
{
1827
177k
  assert(geometry_info != (GeometryInfo *) NULL);
1828
177k
  if (IsEventLogging() != MagickFalse)
1829
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1830
177k
  (void) memset(geometry_info,0,sizeof(*geometry_info));
1831
177k
}