Geometry.cpp revision 641733d57df11b441146f89f9fb1929e999b5e1f
1// This may look like C code, but it is really -*- C++ -*-
2//
3// Copyright Bob Friesenhahn, 1999, 2000, 2001, 2002, 2003
4//
5// Geometry implementation
6//
7
8#define MAGICKCORE_IMPLEMENTATION  1
9#define MAGICK_PLUSPLUS_IMPLEMENTATION 1
10
11#include "Magick++/Include.h"
12#include <string>
13#include <ctype.h> // for isdigit
14
15using namespace std;
16
17#include "Magick++/Geometry.h"
18#include "Magick++/Exception.h"
19
20#define AbsoluteValue(x)  ((x) < 0 ? -(x) : (x))
21
22int Magick::operator == ( const Magick::Geometry& left_,
23			  const Magick::Geometry& right_ )
24{
25  return (
26	  ( left_.isValid()   == right_.isValid() ) &&
27	  ( left_.width()     == right_.width() ) &&
28	  ( left_.height()    == right_.height() ) &&
29	  ( left_.xOff()      == right_.xOff() ) &&
30	  ( left_.yOff()      == right_.yOff() ) &&
31	  ( left_.xNegative() == right_.xNegative() ) &&
32	  ( left_.yNegative() == right_.yNegative() ) &&
33	  ( left_.percent()   == right_.percent() ) &&
34	  ( left_.aspect()    == right_.aspect() ) &&
35	  ( left_.greater()   == right_.greater() ) &&
36	  ( left_.less()      == right_.less() ) &&
37	  ( left_.fillArea()  == right_.fillArea() )
38	  );
39}
40int Magick::operator != ( const Magick::Geometry& left_,
41			  const Magick::Geometry& right_ )
42{
43  return ( ! (left_ == right_) );
44}
45int Magick::operator >  ( const Magick::Geometry& left_,
46			  const Magick::Geometry& right_ )
47{
48  return ( !( left_ < right_ ) && ( left_ != right_ ) );
49}
50int Magick::operator <  ( const Magick::Geometry& left_,
51			  const Magick::Geometry& right_ )
52{
53  return (
54	  ( left_.width() * left_.height() )
55	  <
56	  ( right_.width() * right_.height() )
57	  );
58}
59int Magick::operator >= ( const Magick::Geometry& left_,
60			  const Magick::Geometry& right_ )
61{
62  return ( ( left_ > right_ ) || ( left_ == right_ ) );
63}
64int Magick::operator <= ( const Magick::Geometry& left_,
65			  const Magick::Geometry& right_ )
66{
67  return ( ( left_ < right_ ) || ( left_ == right_ ) );
68}
69
70// Construct using parameterized arguments
71Magick::Geometry::Geometry ( size_t width_,
72			     size_t height_,
73			     ssize_t xOff_,
74			     ssize_t yOff_,
75			     bool xNegative_,
76			     bool yNegative_ )
77  : _width( width_ ),
78    _height( height_ ),
79    _xOff( xOff_ ),
80    _yOff( yOff_ ),
81    _xNegative( xNegative_ ),
82    _yNegative( yNegative_ ),
83    _isValid( true ),
84    _percent( false ),
85    _aspect( false ),
86    _greater( false ),
87    _less( false ),
88    _fillArea( false )
89{
90}
91
92// Assignment from C++ string
93Magick::Geometry::Geometry ( const std::string &geometry_ )
94  : _width( 0 ),
95    _height( 0 ),
96    _xOff( 0 ),
97    _yOff( 0 ),
98    _xNegative( false ),
99    _yNegative( false ),
100    _isValid( false ),
101    _percent( false ),
102    _aspect( false ),
103    _greater( false ),
104    _less( false ),
105    _fillArea( false )
106{
107  *this = geometry_; // Use assignment operator
108}
109
110
111// Assignment from C character string
112Magick::Geometry::Geometry ( const char *geometry_ )
113  : _width( 0 ),
114    _height( 0 ),
115    _xOff( 0 ),
116    _yOff( 0 ),
117    _xNegative( false ),
118    _yNegative( false ),
119    _isValid( false ),
120    _percent( false ),
121    _aspect( false ),
122    _greater( false ),
123    _less( false ),
124    _fillArea( false )
125{
126  *this = geometry_; // Use assignment operator
127}
128
129// Copy constructor
130Magick::Geometry::Geometry ( const Geometry &geometry_ )
131  :  _width( geometry_._width ),
132     _height( geometry_._height ),
133     _xOff( geometry_._xOff ),
134     _yOff( geometry_._yOff ),
135     _xNegative( geometry_._xNegative ),
136     _yNegative( geometry_._yNegative ),
137     _isValid ( geometry_._isValid ),
138     _percent( geometry_._percent ),
139     _aspect( geometry_._aspect ),
140     _greater( geometry_._greater ),
141     _less( geometry_._less ),
142     _fillArea( geometry_._fillArea )
143{
144}
145
146// Default constructor
147Magick::Geometry::Geometry ( void )
148  : _width( 0 ),
149    _height( 0 ),
150    _xOff( 0 ),
151    _yOff( 0 ),
152    _xNegative( false ),
153    _yNegative( false ),
154    _isValid ( false ),
155    _percent( false ),
156    _aspect( false ),
157    _greater( false ),
158    _less( false ),
159    _fillArea( false )
160{
161}
162
163/* virtual */ Magick::Geometry::~Geometry ( void )
164{
165  // Nothing to do
166}
167
168Magick::Geometry& Magick::Geometry::operator = ( const Geometry& geometry_ )
169{
170  // If not being set to ourself
171  if ( this != &geometry_ )
172    {
173      _width = geometry_._width;
174      _height = geometry_._height;
175      _xOff = geometry_._xOff;
176      _yOff = geometry_._yOff;
177      _xNegative = geometry_._xNegative;
178      _yNegative = geometry_._yNegative;
179      _isValid = geometry_._isValid;
180      _percent = geometry_._percent;
181      _aspect = geometry_._aspect;
182      _greater = geometry_._greater;
183      _less = geometry_._less;
184      _fillArea = geometry_._fillArea;
185    }
186  return *this;
187}
188
189// Set value via geometry string
190/* virtual */ const Magick::Geometry&
191Magick::Geometry::operator = ( const std::string &geometry_ )
192{
193  char
194    geom[MaxTextExtent];
195
196  // If argument does not start with digit, presume that it is a
197  // page-size specification that needs to be converted to an
198  // equivalent geometry specification using PostscriptGeometry()
199  (void) CopyMagickString(geom,geometry_.c_str(),MaxTextExtent);
200  if ( geom[0] != '-' &&
201       geom[0] != '+' &&
202       geom[0] != 'x' &&
203       !isdigit(static_cast<int>(geom[0])))
204    {
205      char *pageptr = GetPageGeometry( geom );
206      if ( pageptr != 0 )
207        {
208          (void) CopyMagickString(geom,pageptr,MaxTextExtent);
209          pageptr=(char *) RelinquishMagickMemory( pageptr );
210        }
211    }
212
213  ssize_t x = 0;
214  ssize_t y = 0;
215  size_t width_val = 0;
216  size_t height_val = 0;
217  ssize_t flags = GetGeometry (geom, &x, &y, &width_val, &height_val );
218
219  if (flags == NoValue)
220    {
221      // Total failure!
222      *this=Geometry();
223      isValid( false );
224      return *this;
225    }
226
227  if ( ( flags & WidthValue ) != 0 )
228    {
229      _width = width_val;
230      isValid( true );
231    }
232
233  if ( ( flags & HeightValue ) != 0 )
234    {
235      _height = height_val;
236      isValid( true );
237    }
238
239  if ( ( flags & XValue ) != 0 )
240    {
241      _xOff = static_cast<ssize_t>(x);
242      isValid( true );
243    }
244
245  if ( ( flags & YValue ) != 0 )
246    {
247      _yOff = static_cast<ssize_t>(y);
248      isValid( true );
249    }
250
251  if ( ( flags & XNegative ) != 0 )
252    _xNegative = true;
253
254  if ( ( flags & YNegative ) != 0 )
255    _yNegative = true;
256
257  if ( ( flags & PercentValue ) != 0 )
258    _percent = true;
259
260  if ( ( flags & AspectValue ) != 0 )
261    _aspect = true;
262
263  if ( ( flags & LessValue ) != 0 )
264    _less = true;
265
266  if ( ( flags & GreaterValue ) != 0 )
267    _greater = true;
268
269  if ( ( flags & MinimumValue ) != 0 )
270    _fillArea = true;
271
272  return *this;
273}
274
275
276// Set value via geometry C string
277/* virtual */ const Magick::Geometry& Magick::Geometry::operator = ( const char * geometry_ )
278{
279  *this = std::string(geometry_);
280  return *this;
281}
282
283// Return geometry string
284Magick::Geometry::operator std::string() const
285{
286  if (!isValid())
287    {
288      throwExceptionExplicit( OptionError, "Invalid geometry argument" );
289    }
290
291  string geometry;
292  char buffer[MaxTextExtent];
293
294  if ( _width )
295    {
296      FormatLocaleString( buffer, MaxTextExtent, "%.20g", (double) _width );
297      geometry += buffer;
298    }
299
300  if ( _height )
301    {
302      FormatLocaleString( buffer, MaxTextExtent, "%.20g",  (double) _height);
303      geometry += 'x';
304      geometry +=  buffer;
305    }
306
307  if ( _xOff || _yOff )
308    {
309      if ( _xNegative )
310        geometry += '-';
311      else
312        geometry += '+';
313
314      FormatLocaleString( buffer, MaxTextExtent, "%.20g", (double) _xOff);
315      geometry += buffer;
316
317      if ( _yNegative )
318        geometry += '-';
319      else
320        geometry += '+';
321
322      FormatLocaleString( buffer, MaxTextExtent, "%.20g", (double) _yOff);
323      geometry += buffer;
324    }
325
326  if ( _percent )
327    geometry += '%';
328
329  if ( _aspect )
330    geometry += '!';
331
332  if ( _greater )
333    geometry += '>';
334
335  if ( _less )
336    geometry += '<';
337
338  if ( _fillArea )
339    geometry += '^';
340
341  return geometry;
342}
343
344// Construct from RectangleInfo
345Magick::Geometry::Geometry ( const MagickCore::RectangleInfo &rectangle_ )
346  : _width(static_cast<size_t>(rectangle_.width)),
347    _height(static_cast<size_t>(rectangle_.height)),
348    _xOff(static_cast<ssize_t>(rectangle_.x)),
349    _yOff(static_cast<ssize_t>(rectangle_.y)),
350    _xNegative(rectangle_.x < 0 ? true : false),
351    _yNegative(rectangle_.y < 0 ? true : false),
352    _isValid(true),
353    _percent(false),
354    _aspect(false),
355    _greater(false),
356    _less(false),
357    _fillArea(false)
358{
359}
360
361// Return an ImageMagick RectangleInfo struct
362Magick::Geometry::operator MagickCore::RectangleInfo() const
363{
364  RectangleInfo rectangle;
365  rectangle.width = _width;
366  rectangle.height = _height;
367  _xNegative ? rectangle.x = static_cast<ssize_t>(0-_xOff) : rectangle.x = static_cast<ssize_t>(_xOff);
368  _yNegative ? rectangle.y = static_cast<ssize_t>(0-_yOff) : rectangle.y = static_cast<ssize_t>(_yOff);
369  return rectangle;
370}
371