Color.cpp revision 5c3f4334b3168dc933f5d892289ef1ec556bccc7
1// This may look like C code, but it is really -*- C++ -*-
2//
3// Copyright Bob Friesenhahn, 1999, 2000, 2001, 2002, 2003
4//
5// Color Implementation
6//
7
8#define MAGICKCORE_IMPLEMENTATION
9#define MAGICK_PLUSPLUS_IMPLEMENTATION 1
10
11#include "Magick++/Include.h"
12#include <string>
13
14using namespace std;
15
16#include "Magick++/Color.h"
17#include "Magick++/Exception.h"
18
19//
20// Color operator fuctions
21//
22ssize_t Magick::operator == ( const Magick::Color& left_,
23			  const Magick::Color& right_ )
24{
25  return ( ( left_.isValid()      == right_.isValid() ) &&
26	   ( left_.redQuantum()   == right_.redQuantum() ) &&
27	   ( left_.greenQuantum() == right_.greenQuantum() ) &&
28	   ( left_.blueQuantum()  == right_.blueQuantum() )
29	  );
30}
31ssize_t Magick::operator != ( const Magick::Color& left_,
32			  const Magick::Color& right_ )
33{
34  return ( ! (left_ == right_) );
35}
36ssize_t Magick::operator >  ( const Magick::Color& left_,
37			  const Magick::Color& right_ )
38{
39  return ( !( left_ < right_ ) && ( left_ != right_ ) );
40}
41ssize_t Magick::operator <  ( const Magick::Color& left_,
42			  const Magick::Color& right_ )
43{
44    if(left_.redQuantum() < right_.redQuantum()) return true;
45    if(left_.redQuantum() > right_.redQuantum()) return false;
46    if(left_.greenQuantum() < right_.greenQuantum()) return true;
47    if(left_.greenQuantum() > right_.greenQuantum()) return false;
48    if(left_.blueQuantum() < right_.blueQuantum()) return true;
49    return false;
50}
51ssize_t Magick::operator >= ( const Magick::Color& left_,
52			  const Magick::Color& right_ )
53{
54  return ( ( left_ > right_ ) || ( left_ == right_ ) );
55}
56ssize_t Magick::operator <= ( const Magick::Color& left_,
57			  const Magick::Color& right_ )
58{
59  return ( ( left_ < right_ ) || ( left_ == right_ ) );
60}
61
62//
63// Color Implementation
64//
65
66// Default constructor
67Magick::Color::Color ( void )
68  : _pixel(new PixelPacket),
69    _pixelOwn(true),
70    _isValid(false),
71    _pixelType(RGBPixel)
72{
73  initPixel();
74}
75
76// Construct from RGB
77Magick::Color::Color ( Quantum red_,
78                       Quantum green_,
79                       Quantum blue_ )
80  : _pixel(new PixelPacket),
81    _pixelOwn(true),
82    _isValid(true),
83    _pixelType(RGBPixel)
84{
85  redQuantum   ( red_   );
86  greenQuantum ( green_ );
87  blueQuantum  ( blue_  );
88  alphaQuantum ( OpaqueOpacity );
89}
90
91// Construct from RGBA
92Magick::Color::Color ( Quantum red_,
93                       Quantum green_,
94                       Quantum blue_,
95                       Quantum alpha_ )
96  : _pixel(new PixelPacket),
97    _pixelOwn(true),
98    _isValid(true),
99    _pixelType(RGBAPixel)
100{
101  redQuantum   ( red_   );
102  greenQuantum ( green_ );
103  blueQuantum  ( blue_  );
104  alphaQuantum ( alpha_ );
105}
106
107// Copy constructor
108Magick::Color::Color ( const Magick::Color & color_ )
109  : _pixel( new PixelPacket ),
110    _pixelOwn( true ),
111    _isValid( color_._isValid ),
112    _pixelType( color_._pixelType )
113{
114  *_pixel    = *color_._pixel;
115}
116
117// Construct from color expressed as C++ string
118Magick::Color::Color ( const std::string &x11color_ )
119  : _pixel(new PixelPacket),
120    _pixelOwn(true),
121    _isValid(true),
122    _pixelType(RGBPixel)
123{
124  initPixel();
125
126  // Use operator = implementation
127  *this = x11color_;
128}
129
130// Construct from color expressed as C string
131Magick::Color::Color ( const char * x11color_ )
132  : _pixel(new PixelPacket),
133    _pixelOwn(true),
134    _isValid(true),
135    _pixelType(RGBPixel)
136{
137  initPixel();
138
139  // Use operator = implementation
140  *this = x11color_;
141}
142
143// Construct color via ImageMagick PixelPacket
144Magick::Color::Color ( const PixelPacket &color_ )
145  : _pixel(new PixelPacket),
146    _pixelOwn(true),	    // We allocated this pixel
147    _isValid(true),
148    _pixelType(RGBPixel)  // RGB pixel by default
149{
150  *_pixel = color_;
151
152  if ( color_.opacity != OpaqueOpacity )
153    _pixelType = RGBAPixel;
154}
155
156// Protected constructor to construct with PixelPacket*
157// Used to point Color at a pixel.
158Magick::Color::Color ( PixelPacket* rep_, PixelType pixelType_  )
159  : _pixel(rep_),
160    _pixelOwn(false),
161    _isValid(true),
162    _pixelType(pixelType_)
163{
164}
165
166// Destructor
167Magick::Color::~Color( void )
168{
169  if ( _pixelOwn )
170    delete _pixel;
171  _pixel=0;
172}
173
174// Assignment operator
175Magick::Color& Magick::Color::operator = ( const Magick::Color& color_ )
176{
177  // If not being set to ourself
178  if ( this != &color_ )
179    {
180      // Copy pixel value
181      *_pixel = *color_._pixel;
182
183      // Validity
184      _isValid =  color_._isValid;
185
186      // Copy pixel type
187      _pixelType = color_._pixelType;
188    }
189  return *this;
190}
191
192// Set color via X11 color specification string
193const Magick::Color& Magick::Color::operator = ( const std::string &x11color_ )
194{
195  initPixel();
196  PixelPacket target_color;
197  ExceptionInfo exception;
198  GetExceptionInfo( &exception );
199  if ( QueryColorDatabase( x11color_.c_str(), &target_color, &exception ) )
200    {
201      redQuantum( target_color.red );
202      greenQuantum( target_color.green );
203      blueQuantum( target_color.blue );
204      alphaQuantum( target_color.opacity );
205
206      if ( target_color.opacity > OpaqueOpacity )
207	_pixelType = RGBAPixel;
208      else
209	_pixelType = RGBPixel;
210    }
211  else
212    {
213      _isValid = false;
214      throwException(exception);
215    }
216  (void) DestroyExceptionInfo( &exception );
217
218  return *this;
219}
220
221// Set color via X11 color specification C string
222const Magick::Color& Magick::Color::operator = ( const char * x11color_ )
223{
224  *this = std::string(x11color_);
225  return *this;
226}
227
228// Return X11 color specification string
229Magick::Color::operator std::string() const
230{
231  if ( !isValid() )
232    return std::string("none");
233
234  char colorbuf[MaxTextExtent];
235
236  MagickPixelPacket
237    pixel;
238
239  pixel.colorspace=RGBColorspace;
240  pixel.matte=_pixelType == RGBAPixel ? MagickTrue : MagickFalse;
241  pixel.depth=MAGICKCORE_QUANTUM_DEPTH;
242  pixel.red=_pixel->red;
243  pixel.green=_pixel->green;
244  pixel.blue=_pixel->blue;
245  pixel.opacity=_pixel->opacity;
246  GetColorTuple( &pixel, MagickTrue, colorbuf );
247
248  return std::string(colorbuf);
249}
250
251// Set color via ImageMagick PixelPacket
252const Magick::Color& Magick::Color::operator= ( const MagickCore::PixelPacket &color_ )
253{
254  *_pixel = color_;
255  if ( color_.opacity != OpaqueOpacity )
256    _pixelType = RGBAPixel;
257  else
258    _pixelType = RGBPixel;
259  return *this;
260}
261
262// Set pixel
263// Used to point Color at a pixel in an image
264void Magick::Color::pixel ( PixelPacket* rep_, PixelType pixelType_ )
265{
266  if ( _pixelOwn )
267    delete _pixel;
268  _pixel = rep_;
269  _pixelOwn = false;
270  _isValid = true;
271  _pixelType = pixelType_;
272}
273
274// Does object contain valid color?
275bool Magick::Color::isValid ( void ) const
276{
277  return( _isValid );
278}
279void Magick::Color::isValid ( bool valid_ )
280{
281  if ( (valid_ && isValid()) || (!valid_ && !isValid()) )
282    return;
283
284  if ( !_pixelOwn )
285    {
286      _pixel = new PixelPacket;
287      _pixelOwn = true;
288    }
289
290  _isValid=valid_;
291
292  initPixel();
293}
294
295//
296// ColorHSL Implementation
297//
298
299Magick::ColorHSL::ColorHSL ( double hue_,
300			     double saturation_,
301			     double luminosity_ )
302  : Color ()
303{
304  Quantum red, green, blue;
305
306  ConvertHSLToRGB ( hue_,
307		 saturation_,
308		 luminosity_,
309		 &red,
310		 &green,
311		 &blue );
312
313  redQuantum   ( red );
314  greenQuantum ( green );
315  blueQuantum  ( blue );
316  alphaQuantum ( OpaqueOpacity );
317}
318
319// Null constructor
320Magick::ColorHSL::ColorHSL ( )
321  : Color ()
322{
323}
324
325// Copy constructor from base class
326Magick::ColorHSL::ColorHSL ( const Magick::Color & color_ )
327  : Color( color_ )
328{
329}
330
331// Destructor
332Magick::ColorHSL::~ColorHSL ( )
333{
334  // Nothing to do
335}
336
337void Magick::ColorHSL::hue ( double hue_ )
338{
339  double hue_val, saturation_val, luminosity_val;
340  ConvertRGBToHSL ( redQuantum(),
341		 greenQuantum(),
342		 blueQuantum(),
343		 &hue_val,
344		 &saturation_val,
345		 &luminosity_val );
346
347  hue_val = hue_;
348
349  Quantum red, green, blue;
350  ConvertHSLToRGB ( hue_val,
351		 saturation_val,
352		 luminosity_val,
353		 &red,
354		 &green,
355		 &blue
356		 );
357
358  redQuantum   ( red );
359  greenQuantum ( green );
360  blueQuantum  ( blue );
361}
362
363double Magick::ColorHSL::hue ( void ) const
364{
365  double hue_val, saturation_val, luminosity_val;
366  ConvertRGBToHSL ( redQuantum(),
367		 greenQuantum(),
368		 blueQuantum(),
369		 &hue_val,
370		 &saturation_val,
371		 &luminosity_val );
372  return hue_val;
373}
374
375void Magick::ColorHSL::saturation ( double saturation_ )
376{
377  double hue_val, saturation_val, luminosity_val;
378  ConvertRGBToHSL ( redQuantum(),
379		 greenQuantum(),
380		 blueQuantum(),
381		 &hue_val,
382		 &saturation_val,
383		 &luminosity_val );
384
385  saturation_val = saturation_;
386
387  Quantum red, green, blue;
388  ConvertHSLToRGB ( hue_val,
389		 saturation_val,
390		 luminosity_val,
391		 &red,
392		 &green,
393		 &blue
394		 );
395
396  redQuantum   ( red );
397  greenQuantum ( green );
398  blueQuantum  ( blue );
399}
400
401double Magick::ColorHSL::saturation ( void ) const
402{
403  double hue_val, saturation_val, luminosity_val;
404  ConvertRGBToHSL ( redQuantum(),
405		 greenQuantum(),
406		 blueQuantum(),
407		 &hue_val,
408		 &saturation_val,
409		 &luminosity_val );
410  return saturation_val;
411}
412
413void Magick::ColorHSL::luminosity ( double luminosity_ )
414{
415  double hue_val, saturation_val, luminosity_val;
416  ConvertRGBToHSL ( redQuantum(),
417		 greenQuantum(),
418		 blueQuantum(),
419		 &hue_val,
420		 &saturation_val,
421		 &luminosity_val );
422
423  luminosity_val = luminosity_;
424
425  Quantum red, green, blue;
426  ConvertHSLToRGB ( hue_val,
427		 saturation_val,
428		 luminosity_val,
429		 &red,
430		 &green,
431		 &blue
432		 );
433
434  redQuantum   ( red );
435  greenQuantum ( green );
436  blueQuantum  ( blue );
437}
438
439double Magick::ColorHSL::luminosity ( void ) const
440{
441  double hue_val, saturation_val, luminosity_val;
442  ConvertRGBToHSL ( redQuantum(),
443		 greenQuantum(),
444		 blueQuantum(),
445		 &hue_val,
446		 &saturation_val,
447		 &luminosity_val );
448  return luminosity_val;
449}
450
451// Assignment from base class
452Magick::ColorHSL& Magick::ColorHSL::operator = ( const Magick::Color& color_ )
453{
454  *static_cast<Magick::Color*>(this) = color_;
455  return *this;
456}
457
458//
459// ColorGray Implementation
460//
461Magick::ColorGray::ColorGray ( double shade_ )
462  : Color ( scaleDoubleToQuantum( shade_ ),
463	    scaleDoubleToQuantum( shade_ ),
464	    scaleDoubleToQuantum( shade_ ) )
465{
466  alphaQuantum ( OpaqueOpacity );
467}
468
469// Null constructor
470Magick::ColorGray::ColorGray ( void )
471  : Color ()
472{
473}
474
475// Copy constructor from base class
476Magick::ColorGray::ColorGray ( const Magick::Color & color_ )
477  : Color( color_ )
478{
479}
480
481// Destructor
482Magick::ColorGray::~ColorGray ()
483{
484  // Nothing to do
485}
486
487void Magick::ColorGray::shade ( double shade_ )
488{
489  Quantum gray = scaleDoubleToQuantum( shade_ );
490  redQuantum   ( gray );
491  greenQuantum ( gray );
492  blueQuantum  ( gray );
493}
494
495double Magick::ColorGray::shade ( void ) const
496{
497  return scaleQuantumToDouble ( greenQuantum() );
498}
499
500// Assignment from base class
501Magick::ColorGray& Magick::ColorGray::operator = ( const Magick::Color& color_ )
502{
503  *static_cast<Magick::Color*>(this) = color_;
504  return *this;
505}
506
507//
508// ColorMono Implementation
509//
510Magick::ColorMono::ColorMono ( bool mono_  )
511  : Color ( ( mono_ ? QuantumRange : 0 ),
512	    ( mono_ ? QuantumRange : 0 ),
513	    ( mono_ ? QuantumRange : 0 ) )
514{
515  alphaQuantum ( OpaqueOpacity );
516}
517
518// Null constructor
519Magick::ColorMono::ColorMono ( void )
520  : Color ()
521{
522}
523
524// Copy constructor from base class
525Magick::ColorMono::ColorMono ( const Magick::Color & color_ )
526  : Color( color_ )
527{
528}
529
530// Destructor
531Magick::ColorMono::~ColorMono ()
532{
533  // Nothing to do
534}
535
536void Magick::ColorMono::mono ( bool mono_ )
537{
538  redQuantum   ( mono_ ? QuantumRange : 0 );
539  greenQuantum ( mono_ ? QuantumRange : 0 );
540  blueQuantum  ( mono_ ? QuantumRange : 0 );
541}
542
543bool Magick::ColorMono::mono ( void ) const
544{
545  if ( greenQuantum() )
546    return true;
547  else
548    return false;
549}
550
551// Assignment from base class
552Magick::ColorMono& Magick::ColorMono::operator = ( const Magick::Color& color_ )
553{
554  *static_cast<Magick::Color*>(this) = color_;
555  return *this;
556}
557
558//
559// ColorRGB Implementation
560//
561
562// Construct from red, green, and blue, components
563Magick::ColorRGB::ColorRGB ( double red_,
564			     double green_,
565			     double blue_ )
566  : Color ( scaleDoubleToQuantum(red_),
567	    scaleDoubleToQuantum(green_),
568	    scaleDoubleToQuantum(blue_) )
569{
570  alphaQuantum ( OpaqueOpacity );
571}
572// Null constructor
573Magick::ColorRGB::ColorRGB ( void )
574  : Color ()
575{
576}
577// Copy constructor from base class
578Magick::ColorRGB::ColorRGB ( const Magick::Color & color_ )
579  : Color( color_ )
580{
581}
582// Destructor
583Magick::ColorRGB::~ColorRGB ( void )
584{
585  // Nothing to do
586}
587
588// Assignment from base class
589Magick::ColorRGB& Magick::ColorRGB::operator = ( const Magick::Color& color_ )
590{
591  *static_cast<Magick::Color*>(this) = color_;
592  return *this;
593}
594
595//
596// ColorYUV Implementation
597//
598
599//           R = Y          +1.13980*V
600//           G = Y-0.39380*U-0.58050*V
601//           B = Y+2.02790*U
602//
603//         U and V, normally -0.5 through 0.5, must be normalized to the range 0
604//         through QuantumRange.
605//
606//           Y =  0.29900*R+0.58700*G+0.11400*B
607//           U = -0.14740*R-0.28950*G+0.43690*B
608//           V =  0.61500*R-0.51500*G-0.10000*B
609//
610//         U and V, normally -0.5 through 0.5, are normalized to the range 0
611//         through QuantumRange.  Note that U = 0.493*(B-Y), V = 0.877*(R-Y).
612//
613
614// Construct from color components
615Magick::ColorYUV::ColorYUV ( double y_,
616			     double u_,
617			     double v_ )
618  : Color ( scaleDoubleToQuantum(y_ + 1.13980 * v_ ),
619	    scaleDoubleToQuantum(y_ - (0.39380 * u_) - (0.58050 * v_) ),
620	    scaleDoubleToQuantum(y_ + 2.02790 * u_ ) )
621{
622  alphaQuantum ( OpaqueOpacity );
623}
624// Null constructor
625Magick::ColorYUV::ColorYUV ( void )
626  : Color ()
627{
628}
629// Copy constructor from base class
630Magick::ColorYUV::ColorYUV ( const Magick::Color & color_ )
631  : Color( color_ )
632{
633}
634// Destructor
635Magick::ColorYUV::~ColorYUV ( void )
636{
637  // Nothing to do
638}
639
640void Magick::ColorYUV::u ( double u_ )
641{
642  double V = v();
643  double Y = y();
644
645  redQuantum   ( scaleDoubleToQuantum( Y + 1.13980 * V ) );
646  greenQuantum ( scaleDoubleToQuantum( Y - (0.39380 * u_) - (0.58050 * V) ) );
647  blueQuantum  ( scaleDoubleToQuantum( Y + 2.02790 * u_ ) );
648}
649
650double Magick::ColorYUV::u ( void ) const
651{
652  return scaleQuantumToDouble( (-0.14740 * redQuantum()) - (0.28950 *
653			       greenQuantum()) + (0.43690 * blueQuantum()) );
654}
655
656void Magick::ColorYUV::v ( double v_ )
657{
658  double U = u();
659  double Y = y();
660
661  redQuantum   ( scaleDoubleToQuantum( Y + 1.13980 * v_ ) );
662  greenQuantum ( scaleDoubleToQuantum( Y - (0.39380 * U) - (0.58050 * v_) ) );
663  blueQuantum  ( scaleDoubleToQuantum( Y + 2.02790 * U ) );
664}
665
666double Magick::ColorYUV::v ( void ) const
667{
668  return scaleQuantumToDouble((0.61500 * redQuantum()) -
669                              (0.51500 * greenQuantum()) -
670                              (0.10000 * blueQuantum()));
671}
672
673void Magick::ColorYUV::y ( double y_ )
674{
675  double U = u();
676  double V = v();
677
678  redQuantum   ( scaleDoubleToQuantum( y_ + 1.13980 * V ) );
679  greenQuantum ( scaleDoubleToQuantum( y_ - (0.39380 * U) - (0.58050 * V) ) );
680  blueQuantum  ( scaleDoubleToQuantum( y_ + 2.02790 * U ) );
681}
682
683double Magick::ColorYUV::y ( void ) const
684{
685  return scaleQuantumToDouble((0.29900 * redQuantum()) +
686                              (0.58700 * greenQuantum()) +
687                              (0.11400 * blueQuantum()));
688}
689
690// Assignment from base class
691Magick::ColorYUV& Magick::ColorYUV::operator = ( const Magick::Color& color_ )
692{
693  *static_cast<Magick::Color*>(this) = color_;
694  return *this;
695}
696