Coverage Report

Created: 2026-09-06 07:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/Magick++/lib/Geometry.cpp
Line
Count
Source
1
// This may look like C code, but it is really -*- C++ -*-
2
//
3
// Copyright Bob Friesenhahn, 1999-2026
4
//
5
// Geometry implementation
6
//
7
8
#define MAGICK_IMPLEMENTATION
9
#define MAGICK_PLUSPLUS_IMPLEMENTATION
10
11
#include "Magick++/Include.h"
12
#include <string>
13
#include <ctype.h> // for isdigit
14
#include <iostream>
15
#include <sstream> // for ostringstream
16
#include <string.h> // for strcpy
17
#include <cassert>
18
19
using namespace std;
20
21
#include "Magick++/Geometry.h"
22
#include "Magick++/Exception.h"
23
24
0
#define AbsoluteValue(x)  ((x) < 0 ? -(x) : (x))
25
26
// Does object contain valid geometry?
27
void Magick::Geometry::isValid ( bool isValid_ )
28
0
{
29
0
  _flags._b._isValid = isValid_;
30
0
}
31
32
bool Magick::Geometry::isValid ( void ) const
33
0
{
34
0
  return _flags._b._isValid;
35
0
}
36
37
// Width
38
void Magick::Geometry::width ( unsigned int width_ )
39
0
{
40
0
  _width = width_;
41
0
  isValid( true );
42
0
}
43
unsigned int Magick::Geometry::width ( void ) const
44
0
{
45
0
  return _width;
46
0
}
47
48
// Height
49
void Magick::Geometry::height ( unsigned int height_ )
50
0
{
51
0
  _height = height_;
52
0
}
53
unsigned int Magick::Geometry::height ( void ) const
54
0
{
55
0
  return _height;
56
0
}
57
58
// X offset from origin
59
void Magick::Geometry::xOff ( unsigned int xOff_ )
60
0
{
61
0
  _xOff = xOff_;
62
0
}
63
unsigned int Magick::Geometry::xOff ( void ) const
64
0
{
65
0
  return _xOff;
66
0
}
67
68
// Y offset from origin
69
void Magick::Geometry::yOff ( unsigned int yOff_ )
70
0
{
71
0
  _yOff = yOff_;
72
0
}
73
unsigned int Magick::Geometry::yOff ( void ) const
74
0
{
75
0
  return _yOff;
76
0
}
77
78
// Sign of X offset negative? (X origin at right)
79
void Magick::Geometry::xNegative ( bool xNegative_ )
80
0
{
81
0
  _flags._b._xNegative = xNegative_;
82
0
}
83
bool Magick::Geometry::xNegative ( void ) const
84
0
{
85
0
  return _flags._b._xNegative;
86
0
}
87
88
// Sign of Y offset negative? (Y origin at bottom)
89
void Magick::Geometry::yNegative ( bool yNegative_ )
90
0
{
91
0
  _flags._b._yNegative = yNegative_;
92
0
}
93
bool Magick::Geometry::yNegative ( void ) const
94
0
{
95
0
  return _flags._b._yNegative;
96
0
}
97
98
// Interpret width & height as percentages (%)
99
void Magick::Geometry::percent ( bool percent_ )
100
0
{
101
0
  _flags._b._percent = percent_;
102
0
}
103
bool Magick::Geometry::percent ( void ) const
104
0
{
105
0
  return _flags._b._percent;
106
0
}
107
108
// Resize without preserving aspect ratio (!)
109
void Magick::Geometry::aspect ( bool aspect_ )
110
0
{
111
0
  _flags._b._aspect = aspect_;
112
0
}
113
bool Magick::Geometry::aspect ( void ) const
114
0
{
115
0
  return _flags._b._aspect;
116
0
}
117
118
// Resize if image is greater than size (>)
119
void Magick::Geometry::greater ( bool greater_ )
120
0
{
121
0
  _flags._b._greater = greater_;
122
0
}
123
bool Magick::Geometry::greater ( void ) const
124
0
{
125
0
  return _flags._b._greater;
126
0
}
127
128
// Resize if image is less than size (<)
129
void Magick::Geometry::less ( bool less_ )
130
0
{
131
0
  _flags._b._less = less_;
132
0
}
133
bool Magick::Geometry::less ( void ) const
134
0
{
135
0
  return _flags._b._less;
136
0
}
137
138
// Resize image to fit total pixel area specified by dimensions (@).
139
void Magick::Geometry::limitPixels ( bool limitPixels_ )
140
0
{
141
0
  _flags._b._limitPixels = limitPixels_;
142
0
}
143
bool Magick::Geometry::limitPixels ( void ) const
144
0
{
145
0
  return _flags._b._limitPixels;
146
0
}
147
148
// Resize image to fit a set of dimensions
149
void Magick::Geometry::fillArea ( bool fillArea_ )
150
0
{
151
0
  _flags._b._fillArea = fillArea_;
152
0
}
153
bool Magick::Geometry::fillArea ( void ) const
154
0
{
155
0
  return _flags._b._fillArea;
156
0
}
157
158
159
int Magick::operator == ( const Magick::Geometry& left_,
160
                          const Magick::Geometry& right_ )
161
0
{
162
0
  return (
163
0
          ( left_.isValid()     == right_.isValid() ) &&
164
0
          ( left_.width()       == right_.width() ) &&
165
0
          ( left_.height()      == right_.height() ) &&
166
0
          ( left_.xOff()        == right_.xOff() ) &&
167
0
          ( left_.yOff()        == right_.yOff() ) &&
168
0
          ( left_.xNegative()   == right_.xNegative() ) &&
169
0
          ( left_.yNegative()   == right_.yNegative() ) &&
170
0
          ( left_.percent()     == right_.percent() ) &&
171
0
          ( left_.aspect()      == right_.aspect() ) &&
172
0
          ( left_.greater()     == right_.greater() ) &&
173
0
          ( left_.less()        == right_.less() ) &&
174
0
          ( left_.limitPixels() == right_.limitPixels() ) &&
175
0
          ( left_.fillArea()    == right_.fillArea() )
176
0
          );
177
0
}
178
int Magick::operator != ( const Magick::Geometry& left_,
179
                          const Magick::Geometry& right_ )
180
0
{
181
0
  return ( ! (left_ == right_) );
182
0
}
183
int Magick::operator >  ( const Magick::Geometry& left_,
184
                          const Magick::Geometry& right_ )
185
0
{
186
0
  return ( !( left_ < right_ ) && ( left_ != right_ ) );
187
0
}
188
int Magick::operator <  ( const Magick::Geometry& left_,
189
                          const Magick::Geometry& right_ )
190
0
{
191
0
  return (
192
0
          ( left_.width() * left_.height() )
193
0
          <
194
0
          ( right_.width() * right_.height() )
195
0
          );
196
0
}
197
int Magick::operator >= ( const Magick::Geometry& left_,
198
                          const Magick::Geometry& right_ )
199
0
{
200
0
  return ( ( left_ > right_ ) || ( left_ == right_ ) );
201
0
}
202
int Magick::operator <= ( const Magick::Geometry& left_,
203
                          const Magick::Geometry& right_ )
204
0
{
205
0
  return ( ( left_ < right_ ) || ( left_ == right_ ) );
206
0
}
207
208
// Construct using parameterized arguments
209
Magick::Geometry::Geometry ( unsigned int width_,
210
                             unsigned int height_,
211
                             unsigned int xOff_,
212
                             unsigned int yOff_,
213
                             bool xNegative_,
214
                             bool yNegative_ )
215
0
  : _width( width_ ),
216
0
    _height( height_ ),
217
0
    _xOff( xOff_ ),
218
0
    _yOff( yOff_ )
219
0
{
220
0
  xNegative( xNegative_ );
221
0
  yNegative( yNegative_ );
222
0
  isValid( true );
223
0
  percent( false );
224
0
  aspect( false );
225
0
  greater( false );
226
0
  less( false );
227
0
  limitPixels (false );
228
0
  fillArea( false );
229
0
}
230
231
// Assignment from C++ string
232
Magick::Geometry::Geometry ( const std::string &geometry_ )
233
0
  : _width( 0 ),
234
0
    _height( 0 ),
235
0
    _xOff( 0 ),
236
0
    _yOff( 0 )
237
0
{
238
0
  assert(sizeof(_flags._padding) >= sizeof(_flags._b));
239
0
  xNegative( false );
240
0
  yNegative( false );
241
0
  isValid( false );
242
0
  percent( false );
243
0
  aspect( false );
244
0
  greater( false );
245
0
  less( false );
246
0
  limitPixels (false );
247
0
  fillArea( false );
248
0
  *this = geometry_; // Use assignment operator
249
0
}
250
251
252
// Assignment from C character string
253
Magick::Geometry::Geometry ( const char *geometry_ )
254
0
  : _width( 0 ),
255
0
    _height( 0 ),
256
0
    _xOff( 0 ),
257
0
    _yOff( 0 )
258
0
{
259
0
  xNegative( false );
260
0
  yNegative( false );
261
0
  isValid( false );
262
0
  percent( false );
263
0
  aspect( false );
264
0
  greater( false );
265
0
  less( false );
266
0
  limitPixels ( false );
267
0
  fillArea( false );
268
0
  *this = geometry_; // Use assignment operator
269
0
}
270
271
// Copy constructor
272
Magick::Geometry::Geometry ( const Geometry &geometry_ )
273
0
  :  _width( geometry_._width ),
274
0
     _height( geometry_._height ),
275
0
     _xOff( geometry_._xOff ),
276
0
     _yOff( geometry_._yOff )
277
0
{
278
0
  xNegative( geometry_.xNegative() );
279
0
  yNegative( geometry_.yNegative() );
280
0
  isValid ( geometry_.isValid() );
281
0
  percent( geometry_.percent() );
282
0
  aspect( geometry_.aspect() );
283
0
  greater( geometry_.greater() );
284
0
  less( geometry_.less() );
285
0
  limitPixels( geometry_.limitPixels() );
286
0
  fillArea( geometry_.fillArea() );
287
0
}
288
289
// Default constructor
290
Magick::Geometry::Geometry ( void )
291
0
  : _width( 0 ),
292
0
    _height( 0 ),
293
0
    _xOff( 0 ),
294
0
    _yOff( 0 )
295
0
{
296
0
  assert(sizeof(_flags._padding) >= sizeof(_flags._b));
297
0
  xNegative( false );
298
0
  yNegative( false );
299
0
  isValid ( false );
300
0
  percent( false );
301
0
  aspect( false );
302
0
  greater( false );
303
0
  less( false );
304
0
  limitPixels( false );
305
0
  fillArea( false );
306
0
}
307
308
/* virtual */ Magick::Geometry::~Geometry ( void )
309
0
{
310
  // Nothing to do
311
0
}
312
313
Magick::Geometry& Magick::Geometry::operator = ( const Geometry& geometry_ )
314
0
{
315
  // If not being set to ourself
316
0
  if ( this != &geometry_ )
317
0
    {
318
0
      _width = geometry_._width;
319
0
      _height = geometry_._height;
320
0
      _xOff = geometry_._xOff;
321
0
      _yOff = geometry_._yOff;
322
323
0
      xNegative( geometry_.xNegative() );
324
0
      yNegative( geometry_.yNegative() );
325
0
      isValid ( geometry_.isValid() );
326
0
      percent( geometry_.percent() );
327
0
      aspect( geometry_.aspect() );
328
0
      greater( geometry_.greater() );
329
0
      less( geometry_.less() );
330
0
      limitPixels( geometry_.limitPixels() );
331
0
      fillArea( geometry_.fillArea() );
332
0
    }
333
0
  return *this;
334
0
}
335
336
// Set value via geometry string
337
/* virtual */ const Magick::Geometry&
338
Magick::Geometry::operator = ( const std::string &geometry_ )
339
0
{
340
  // If argument does not start with digit, presume that it is a
341
  // page-size specification that needs to be converted to an
342
  // equivalent geometry specification using PostscriptGeometry()
343
0
  std::string geom = geometry_;
344
0
  if (geom[0] != '-' &&
345
0
      geom[0] != '+' &&
346
0
      geom[0] != 'x' &&
347
0
      !std::isdigit(static_cast<int>(geom[0])))
348
0
    {
349
0
      char *pageptr = GetPageGeometry( geom.c_str() );
350
0
      if ( pageptr != 0 )
351
0
        {
352
0
          geom = pageptr;
353
0
          MagickFreeMemory(pageptr);
354
0
        }
355
0
    }
356
357
0
  long x = 0;
358
0
  long y = 0;
359
0
  unsigned long width_val = 0;
360
0
  unsigned long height_val = 0;
361
0
  int flags = GetGeometry (geom.c_str(), &x, &y, &width_val, &height_val );
362
363
0
  if (flags == NoValue)
364
0
    {
365
      // Total failure!
366
0
      *this=Geometry();
367
0
      isValid( false );
368
0
      return *this;
369
0
    }
370
371
0
  if ( ( flags & WidthValue ) != 0 )
372
0
    {
373
0
      width( width_val );
374
0
      isValid( true );
375
0
    }
376
377
0
  if ( ( flags & HeightValue ) != 0 )
378
0
    height( height_val );
379
380
0
  if ( ( flags & XValue ) != 0 )
381
0
    {
382
0
      xOff( static_cast<unsigned int>(AbsoluteValue(x)) );
383
0
      isValid( true );
384
0
    }
385
386
0
  if ( ( flags & YValue ) != 0 )
387
0
    {
388
0
      yOff( static_cast<unsigned int>(AbsoluteValue(y)) );
389
0
      isValid( true );
390
0
    }
391
392
0
  if ( ( flags & XNegative ) != 0 )
393
0
    xNegative( true );
394
395
0
  if ( ( flags & YNegative ) != 0 )
396
0
    yNegative( true );
397
398
0
  if ( ( flags & PercentValue ) != 0 ) // '%'
399
0
    percent( true );
400
401
0
  if ( ( flags & AspectValue ) != 0 )  // '!'
402
0
    aspect( true );
403
404
0
  if ( ( flags & LessValue ) != 0 )    // '<'
405
0
    less( true );
406
407
0
  if ( ( flags & GreaterValue ) != 0 ) // '>'
408
0
    greater( true );
409
410
0
  if ( ( flags & AreaValue ) != 0 )    // '@'
411
0
    limitPixels( true );
412
413
0
  if ( ( flags & MinimumValue ) != 0 ) // '^'
414
0
    fillArea( true );
415
416
0
  return *this;
417
0
}
418
419
420
// Set value via geometry C string
421
/* virtual */ const Magick::Geometry& Magick::Geometry::operator = ( const char * geometry_ )
422
0
{
423
0
  *this = std::string(geometry_);
424
0
  return *this;
425
0
}
426
427
// Return geometry string
428
Magick::Geometry::operator std::string() const
429
0
{
430
0
  if (!isValid())
431
0
    {
432
0
      throwExceptionExplicit( OptionError, "Invalid geometry argument" );
433
0
    }
434
435
0
  string geometry;
436
0
  std::ostringstream oss;
437
438
0
   if ( _width )
439
0
    {
440
0
      oss << _width;
441
0
    }
442
443
0
   if ( _width && _height )
444
0
     {
445
0
       oss << 'x'
446
0
           << _height;
447
0
     }
448
449
0
   if ( _xOff || _yOff )
450
0
    {
451
0
      if ( xNegative() )
452
0
        oss << '-';
453
0
      else
454
0
        oss << '+';
455
456
0
      oss << _xOff;
457
458
0
      if ( yNegative() )
459
0
        oss << '-';
460
0
      else
461
0
        oss << '+';
462
463
0
      oss << _yOff;
464
0
    }
465
466
0
   if ( percent() )
467
0
     oss << '%';
468
469
0
  if ( aspect() )
470
0
    oss << '!';
471
472
0
  if ( greater() )
473
0
    oss << '>';
474
475
0
  if ( less() )
476
0
    oss << '<';
477
478
0
  if ( limitPixels() )
479
0
    oss << '@';
480
481
0
  if ( fillArea() )
482
0
    oss << '^';
483
484
0
  geometry = oss.str();
485
486
0
  return geometry;
487
0
}
488
489
// Construct from RectangleInfo
490
Magick::Geometry::Geometry ( const MagickLib::RectangleInfo &rectangle_ )
491
0
  : _width(static_cast<unsigned int>(rectangle_.width)),
492
0
    _height(static_cast<unsigned int>(rectangle_.height)),
493
0
    _xOff(static_cast<unsigned int>(AbsoluteValue(rectangle_.x))),
494
0
    _yOff(static_cast<unsigned int>(AbsoluteValue(rectangle_.y)))
495
0
{
496
0
  xNegative(rectangle_.x < 0 ? true : false);
497
0
  yNegative(rectangle_.y < 0 ? true : false);
498
0
  isValid(true);
499
0
  percent(false);
500
0
  aspect(false);
501
0
  greater(false);
502
0
  less(false);
503
0
  limitPixels(false);
504
0
  fillArea(false);
505
0
}
506
507
// Return an ImageMagick RectangleInfo struct
508
Magick::Geometry::operator MagickLib::RectangleInfo() const
509
0
{
510
0
  RectangleInfo rectangle;
511
0
  rectangle.width = _width;
512
0
  rectangle.height = _height;
513
0
  xNegative() ? rectangle.x = static_cast<long>(0-_xOff) : rectangle.x = static_cast<long>(_xOff);
514
0
  yNegative() ? rectangle.y = static_cast<long>(0-_yOff) : rectangle.y = static_cast<long>(_yOff);
515
0
  return rectangle;
516
0
}