Milena (Olena)  User documentation 2.0a Id
 All Classes Namespaces Functions Variables Typedefs Enumerator Groups Pages
value/rgb.hh
1 // Copyright (C) 2007, 2008, 2009, 2010 EPITA Research and Development
2 // Laboratory (LRDE)
3 //
4 // This file is part of Olena.
5 //
6 // Olena is free software: you can redistribute it and/or modify it under
7 // the terms of the GNU General Public License as published by the Free
8 // Software Foundation, version 2 of the License.
9 //
10 // Olena is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Olena. If not, see <http://www.gnu.org/licenses/>.
17 //
18 // As a special exception, you may use this file as part of a free
19 // software project without restriction. Specifically, if other files
20 // instantiate templates or use macros or inline functions from this
21 // file, or you compile this file and link it with other files to produce
22 // an executable, this file does not by itself cause the resulting
23 // executable to be covered by the GNU General Public License. This
24 // exception does not however invalidate any other reasons why the
25 // executable file might be covered by the GNU General Public License.
26 
27 #ifndef MLN_VALUE_RGB_HH
28 # define MLN_VALUE_RGB_HH
29 
30 
31 # include <mln/value/ops.hh>
32 
33 # include <mln/fun/v2v/hsl_to_rgb.hh>
34 # include <mln/value/concept/vectorial.hh>
35 # include <mln/value/int_u.hh>
36 # include <mln/algebra/vec.hh>
37 
38 # include <mln/value/internal/make_generic_name.hh>
39 
40 # include <mln/convert/from_to.hh>
41 
42 // FIXME: should we consider that mln_min may be negative? => wrong
43 // color formulae.
44 
45 namespace mln
46 {
47 
48  // Forward declaration.
49  namespace value { template <unsigned n> struct rgb; }
50 
51 
52 
53  namespace fun
54  {
55 
56  namespace v2v
57  {
58 
59  template <typename T_rgb>
60  struct f_hsl_to_rgb_;
61 
62  typedef f_hsl_to_rgb_< value::rgb<8> > f_hsl_to_rgb_3x8_t;
63 // typedef f_hsl_to_rgb_< value::rgb<16> > f_hsl_to_rgb_3x16_t;
64 
65  extern f_hsl_to_rgb_3x8_t f_hsl_to_rgb_3x8;
66 // extern f_hsl_to_rgb_3x16_t f_hsl_to_rgb_3x16;
67 
68  }
69 
70  }
71 
72 
73  namespace literal
74  {
76  struct black_t;
77  struct white_t;
78 
79  struct light_gray_t;
80  struct medium_gray_t;
81  struct dark_gray_t;
82 
83  struct red_t;
84  struct green_t;
85  struct blue_t;
86  struct brown_t;
87  struct lime_t;
88  struct orange_t;
89  struct pink_t;
90  struct purple_t;
91  struct teal_t;
92  struct violet_t;
93  struct cyan_t;
94  struct magenta_t;
95  struct yellow_t;
96  struct olive_t;
98  }
99 
100 
101  // Forward declaration.
102  namespace value
103  {
104  template <typename H, typename S, typename L> class hsl_;
105  }
106 
107 
108  namespace convert
109  {
110 
111  namespace over_load
112  {
113 
114  // algebra::vec -> rgb.
115  template <typename T, unsigned m>
116  void from_to_(const algebra::vec<3,T>& from, value::rgb<m>& to_);
117 
118  // bool -> rgb.
119  template <unsigned m>
120  void from_to_(bool from, value::rgb<m>& to);
121 
122  // int_u -> rgb.
123  template <unsigned m>
124  void from_to_(const value::int_u<m>& from, value::rgb<m>& to);
125 
126  // hsl -> rgb8.
127  template <typename H, typename S, typename L>
128  void from_to_(const value::hsl_<H,S,L>&, value::rgb<8>& to);
129 
130 // // hsl -> rgb16.
131 // template <typename H, typename S, typename L>
132 // void from_to_(const value::hsl_<H,S,L>&, value::rgb<16>& to);
133 
134  // rgb -> bool.
135  template <unsigned m>
136  void from_to_(const value::rgb<m>& from, bool& to);
137 
138  } // end of namespace mln::convert::over_load
139 
140  } // end of namespace mln::convert
141 
142 
143  namespace trait
144  {
145  template < unsigned n >
146  struct set_precise_binary_< op::plus, mln::value::rgb<n>, mln::value::rgb<n> >
147  {
148  typedef mln::value::rgb<n> ret;
149  };
150 
151  template < unsigned n >
152  struct set_precise_binary_< op::minus, mln::value::rgb<n>, mln::value::rgb<n> >
153  {
154  typedef mln::value::rgb<n> ret;
155  };
156 
157  template < unsigned n, typename S >
158  struct set_precise_binary_< op::times, mln::value::rgb<n>, mln::value::scalar_<S> >
159  {
160  typedef mln::value::rgb<n> ret;
161  };
162 
163  template < unsigned n, typename S >
164  struct set_precise_binary_< op::div, mln::value::rgb<n>, mln::value::scalar_<S> >
165  {
166  typedef mln::value::rgb<n> ret;
167  };
168 
169 
170  // FIXME : Is there any way more generic? a way to factor
171  // set_precise_binary_< op::div, mln::value::rgb<n>, mln::value::scalar_<S> >
172  // and
173  // set_precise_binary_< op::div, mln::value::rgb<n>, mln::value::int_u<m> >
174  // as for op::times.
175 
176  template < unsigned n, unsigned m >
177  struct set_precise_binary_< op::times, mln::value::rgb<n>, mln::value::int_u<m> >
178  {
179  typedef mln::value::rgb<n> ret;
180  };
181 
182  template < unsigned n, unsigned m >
183  struct set_precise_binary_< op::div, mln::value::rgb<n>, mln::value::int_u<m> >
184  {
185  typedef mln::value::rgb<n> ret;
186  };
187 
188 
189 // template < unsigned n, typename I >
190 // struct set_binary_< op::times,
191 // mln::value::Vectorial, mln::value::rgb<n>,
192 // mln::value::Integer, I >
193 // {
194 // typedef mln::value::rgb<n> ret;
195 // };
196 
197 // template < unsigned n, typename S >
198 // struct set_binary_< op::times,
199 // mln::value::Scalar, S,
200 // mln::value::Vectorial, mln::value::rgb<n> >
201 // {
202 // typedef mln::value::rgb<n> ret;
203 // };
204 
205  template <unsigned n>
206  struct value_< mln::value::rgb<n> >
207  {
208  enum {
209  dim = 3,
210  nbits = dim * n,
211  card = mln_value_card_from_(nbits)
212  };
213 
214  typedef trait::value::nature::vectorial nature;
215  typedef trait::value::kind::color kind;
216  typedef trait::value::quant::high /*mln_value_quant_from_(card)*/ quant;
217 
218  typedef void comp;
219  typedef mln::value::int_u<n> comp_0;
220  typedef mln::value::int_u<n> comp_1;
221  typedef mln::value::int_u<n> comp_2;
222 
223  template <typename V> static comp_0 get_comp_0(const V& v) { return v.red(); }
224  template <typename V> static comp_1 get_comp_1(const V& v) { return v.green(); }
225  template <typename V> static comp_2 get_comp_2(const V& v) { return v.blue(); }
226 
227  typedef algebra::vec<dim, float> sum;
228 
229  static const char* name()
230  {
231  static std::string
232  s = mln::value::internal::make_generic_name("rgb", n);
233  return s.c_str();
234  }
235 
236  };
237 
238  } // end of namespace trait
239 
240 
241 
242  namespace value
243  {
244 
247  template <unsigned n>
248  struct rgb
249  :
250  public Vectorial< rgb<n> >
251  ,
252  public internal::value_like_< algebra::vec< 3, int_u<n> >, // Equivalent.
253  algebra::vec< 3, int_u<n> >, // Encoding.
254  algebra::vec< 3, int >, // Interoperation.
255  rgb<n> > // Exact.
256  {
257  public:
258 
259  typedef int_u<n> red_t;
260  typedef int_u<n> green_t;
261  typedef int_u<n> blue_t;
262 
264  int_u<n> red() const { return this->v_[0]; }
265  int_u<n>& red() { return this->v_[0]; }
266 
267  int_u<n> green() const { return this->v_[1]; }
268  int_u<n>& green() { return this->v_[1]; }
269 
270  int_u<n> blue() const { return this->v_[2]; }
271  int_u<n>& blue() { return this->v_[2]; }
272 
273  int_u<n> comp(unsigned k) const { return this->v_[k]; }
274  int_u<n>& comp(unsigned k) { return this->v_[k]; }
276 
278  rgb<n>();
279 
281  rgb<n>(int r, int g, int b);
282 
284  rgb<n>(const algebra::vec<3, int>& rhs);
285  rgb<n>(const algebra::vec<3, unsigned>& rhs);
286  rgb<n>(const algebra::vec<3, int_u<n> >& rhs);
287  rgb<n>(const algebra::vec<3, float>& rhs);
288 
289  // Conversion to the interoperation type.
290  operator algebra::vec<3, int>() const { return this->v_; }
291  // Conversion to the sum type.
292  operator algebra::vec<3, float>() const { return this->v_; }
293 
295  rgb<n>(const mln::literal::white_t&);
296  rgb<n>(const mln::literal::black_t&);
297 
298  rgb<n>(const mln::literal::light_gray_t&);
299  rgb<n>(const mln::literal::medium_gray_t&);
300  rgb<n>(const mln::literal::dark_gray_t&);
301 
302  rgb<n>(const mln::literal::red_t&);
303  rgb<n>(const mln::literal::blue_t&);
304  rgb<n>(const mln::literal::green_t&);
305  rgb<n>(const mln::literal::brown_t&);
306  rgb<n>(const mln::literal::lime_t&);
307  rgb<n>(const mln::literal::orange_t&);
308  rgb<n>(const mln::literal::pink_t&);
309  rgb<n>(const mln::literal::purple_t&);
310  rgb<n>(const mln::literal::teal_t&);
311  rgb<n>(const mln::literal::violet_t&);
312  rgb<n>(const mln::literal::cyan_t&);
313  rgb<n>(const mln::literal::magenta_t&);
314  rgb<n>(const mln::literal::yellow_t&);
315  rgb<n>(const mln::literal::olive_t&);
317 
319  rgb<n>& operator=(const rgb<n>& rhs);
320 
322  static const rgb<n> zero;
323  };
324 
325 
326 
333  template <unsigned n>
334  std::ostream& operator<<(std::ostream& ostr, const rgb<n>& c);
335 
336  template <unsigned n>
337  std::istream& operator>>(std::istream& istr, rgb<n>& c);
338 
339 
340  /* FIXME: We should not need to define these operators, thanks to
341  Milena's global operator resolution mechanism based on
342  mln::Object. See what prevent us to use this mechanism. */
343 
344  /* FIXME: Cannot work for i negative; add traits! (2008-02-16,
345  Roland: What does this comment mean?) */
346 
349  template <unsigned n>
350  typename rgb<n>::interop
351  operator+(const rgb<n>& lhs, const rgb<n>& rhs);
352 
353  template <unsigned n>
354  typename rgb<n>::interop
355  operator+(const typename rgb<n>::interop& lhs, const rgb<n>& rhs);
356 
357  template <unsigned n>
358  typename rgb<n>::interop
359  operator+(const rgb<n>& lhs, const typename rgb<n>::interop& rhs);
361 
364  template <unsigned n>
365  typename rgb<n>::interop
366  operator-(const rgb<n>& lhs, const rgb<n>& rhs);
367 
368  template <unsigned n>
369  typename rgb<n>::interop
370  operator-(const typename rgb<n>::interop& lhs, const rgb<n>& rhs);
371 
372  template <unsigned n>
373  typename rgb<n>::interop
374  operator-(const rgb<n>& lhs, const typename rgb<n>::interop& rhs);
376 
379  template <unsigned n, typename S>
380  inline
381  typename rgb<n>::interop
382  operator*(const rgb<n>& lhs, const mln::value::scalar_<S>& s);
383 
384  template <unsigned n, typename S>
385  inline
386  typename rgb<n>::interop
387  operator*(const mln::value::scalar_<S>& s, const rgb<n>& lhs);
389 
392  template <unsigned n, typename S>
393  inline
394  typename rgb<n>::interop
395  operator/(const rgb<n>& lhs, const mln::value::scalar_<S>& s);
397 
398 
399  } // end of namespace mln::value
400 
401 } // end of namespace mln
402 
403 
404 // // Needed by from_to_.
405 // # include <mln/fun/v2v/rgb_to_hsl.hh>
406 
407 
408 # ifndef MLN_INCLUDE_ONLY
409 
410 namespace mln
411 {
412 
413  namespace value
414  {
415 
416  /*---------------.
417  | Construction. |
418  `---------------*/
419 
420  template <unsigned n>
421  inline
423  {
424  }
425 
426  template <unsigned n>
427  inline
428  rgb<n>::rgb(const algebra::vec<3, int>& v)
429  {
430  this->v_ = v;
431  }
432 
433  template <unsigned n>
434  inline
435  rgb<n>::rgb(const algebra::vec<3, unsigned>& v)
436  {
437  this->v_ = v;
438  }
439 
440  template <unsigned n>
441  inline
442  rgb<n>::rgb(const algebra::vec<3, int_u<n> >& v)
443  {
444  this->v_ = v;
445  }
446 
447  template <unsigned n>
448  inline
449  rgb<n>::rgb(const algebra::vec<3, float>& v)
450  {
451  convert::from_to(v[0], this->v_[0]);
452  convert::from_to(v[1], this->v_[1]);
453  convert::from_to(v[2], this->v_[2]);
454  }
455 
456  template <unsigned n>
457  inline
458  rgb<n>::rgb(int r, int g, int b)
459  {
460  mln_precondition(r >= 0);
461  mln_precondition(g >= 0);
462  mln_precondition(b >= 0);
463  mln_precondition(unsigned(r) <= mln_max(int_u<n>));
464  mln_precondition(unsigned(g) <= mln_max(int_u<n>));
465  mln_precondition(unsigned(b) <= mln_max(int_u<n>));
466  this->v_[0] = r;
467  this->v_[1] = g;
468  this->v_[2] = b;
469  }
470 
471  template <unsigned n>
472  inline
474  {
475  this->v_[0] = mln_max(int_u<n>);
476  this->v_[1] = mln_max(int_u<n>);
477  this->v_[2] = mln_max(int_u<n>);
478  }
479 
480  template <unsigned n>
481  inline
483  {
484  this->v_[0] = 0;
485  this->v_[1] = 0;
486  this->v_[2] = 0;
487  }
488 
489  template <unsigned n>
490  inline
492  {
493  convert::from_to(mln_max(int_u<n>) * 0.75, this->v_[0]);
494  convert::from_to(mln_max(int_u<n>) * 0.75, this->v_[1]);
495  convert::from_to(mln_max(int_u<n>) * 0.75, this->v_[2]);
496  }
497 
498  template <unsigned n>
499  inline
500  rgb<n>::rgb(const mln::literal::medium_gray_t&)
501  {
502  convert::from_to(mln_max(int_u<n>) * 0.50, this->v_[0]);
503  convert::from_to(mln_max(int_u<n>) * 0.50, this->v_[1]);
504  convert::from_to(mln_max(int_u<n>) * 0.50, this->v_[2]);
505  }
506 
507  template <unsigned n>
508  inline
509  rgb<n>::rgb(const mln::literal::dark_gray_t&)
510  {
511  convert::from_to(mln_max(int_u<n>) * 0.25, this->v_[0]);
512  convert::from_to(mln_max(int_u<n>) * 0.25, this->v_[1]);
513  convert::from_to(mln_max(int_u<n>) * 0.25, this->v_[2]);
514  }
515 
516  template <unsigned n>
517  inline
519  {
520  this->v_[0] = mln_max(int_u<n>);
521  this->v_[1] = 0;
522  this->v_[2] = 0;
523  }
524 
525  template <unsigned n>
526  inline
528  {
529  this->v_[0] = 0;
530  this->v_[1] = mln_max(int_u<n>);
531  this->v_[2] = 0;
532  }
533 
534  template <unsigned n>
535  inline
537  {
538  this->v_[0] = 0;
539  this->v_[1] = 0;
540  this->v_[2] = mln_max(int_u<n>);
541  }
542 
543  template <unsigned n>
544  inline
546  {
547  convert::from_to(mln_max(int_u<n>) * 0.75, this->v_[0]);
548  convert::from_to(mln_max(int_u<n>) * 0.50, this->v_[1]);
549  convert::from_to(mln_max(int_u<n>) * 0.25, this->v_[2]);
550  }
551 
552  template <unsigned n>
553  inline
555  {
556  convert::from_to(mln_max(int_u<n>) * 0.75, this->v_[0]);
557  this->v_[1] = mln_max(int_u<n>);
558  this->v_[2] = 0;
559  }
560 
561  template <unsigned n>
562  inline
564  {
565  this->v_[0] = mln_max(int_u<n>);
566  convert::from_to(mln_max(int_u<n>) * 0.50, this->v_[1]);
567  this->v_[2] = 0;
568  }
569 
570  template <unsigned n>
571  inline
573  {
574  this->v_[0] = mln_max(int_u<n>);
575  convert::from_to(mln_max(int_u<n>) * 0.75, this->v_[1]);
576  convert::from_to(mln_max(int_u<n>) * 0.75, this->v_[2]);
577  }
578 
579  template <unsigned n>
580  inline
582  {
583  convert::from_to(mln_max(int_u<n>) * 0.75, this->v_[0]);
584  this->v_[1] = 0;
585  convert::from_to(mln_max(int_u<n>) * 0.25, this->v_[2]);
586  }
587 
588  template <unsigned n>
589  inline
591  {
592  this->v_[0] = 0;
593  convert::from_to(mln_max(int_u<n>) * 0.50, this->v_[1]);
594  convert::from_to(mln_max(int_u<n>) * 0.50, this->v_[2]);
595  }
596 
597  template <unsigned n>
598  inline
600  {
601  convert::from_to(mln_max(int_u<n>) * 0.50, this->v_[0]);
602  this->v_[1] = 0;
603  convert::from_to(mln_max(int_u<n>) * 0.50, this->v_[2]);
604  }
605 
606  template <unsigned n>
607  inline
609  {
610  this->v_[0] = 0;
611  this->v_[1] = mln_max(int_u<n>);
612  this->v_[2] = mln_max(int_u<n>);
613  }
614 
615  template <unsigned n>
616  inline
618  {
619  this->v_[0] = mln_max(int_u<n>);
620  this->v_[1] = 0;
621  this->v_[2] = mln_max(int_u<n>);
622  }
623 
624  template <unsigned n>
625  inline
627  {
628  this->v_[0] = mln_max(int_u<n>);
629  this->v_[1] = mln_max(int_u<n>);
630  this->v_[2] = 0;
631  }
632 
633  template <unsigned n>
634  inline
636  {
637  convert::from_to(mln_max(int_u<n>) * 0.50, this->v_[0]);
638  convert::from_to(mln_max(int_u<n>) * 0.50, this->v_[1]);
639  this->v_[2] = 0;
640  }
641 
642  template <unsigned n>
643  inline
644  rgb<n>&
646  {
647  if (& rhs == this)
648  return *this;
649  this->v_ = rhs.v_;
650  return *this;
651  }
652 
653  template <unsigned n>
654  const rgb<n> rgb<n>::zero(0,0,0);
655 
656  /*------------.
657  | Operators. |
658  `------------*/
659 
660  template <unsigned n>
661  inline
662  typename rgb<n>::interop
663  operator+(const rgb<n>& lhs, const rgb<n>& rhs)
664  {
665  typename rgb<n>::interop tmp(lhs.to_interop() + rhs.to_interop());
666  return tmp;
667  }
668 
669  template <unsigned n>
670  inline
671  typename rgb<n>::interop
672  operator+(const rgb<n>& lhs, const typename rgb<n>::interop& rhs)
673  {
674  typename rgb<n>::interop tmp(lhs.to_interop() + rhs);
675  return tmp;
676  }
677 
678  template <unsigned n>
679  inline
680  typename rgb<n>::interop
681  operator+(const typename rgb<n>::interop& lhs, const rgb<n>& rhs)
682  {
683  typename rgb<n>::interop tmp(lhs + rhs.to_interop());
684  return tmp;
685  }
686 
687  template <unsigned n>
688  inline
689  typename rgb<n>::interop
690  operator-(const rgb<n>& lhs, const rgb<n>& rhs)
691  {
692  typename rgb<n>::interop tmp(lhs.to_interop() - rhs.to_interop());
693  return tmp;
694  }
695 
696  template <unsigned n>
697  inline
698  typename rgb<n>::interop
699  operator-(const rgb<n>& lhs, const typename rgb<n>::interop& rhs)
700  {
701  typename rgb<n>::interop tmp(lhs.to_interop() - rhs);
702  return tmp;
703  }
704 
705  template <unsigned n>
706  inline
707  typename rgb<n>::interop
708  operator-(const typename rgb<n>::interop& lhs, const rgb<n>& rhs)
709  {
710  typename rgb<n>::interop tmp(lhs - rhs.to_interop());
711  return tmp;
712  }
713 
714  template <unsigned n, typename S>
715  inline
716  typename rgb<n>::interop
717  operator*(const rgb<n>& lhs, const mln::value::scalar_<S>& s)
718  {
719  typename rgb<n>::interop tmp(lhs.to_interop() * s.to_equiv());
720  return tmp;
721  }
722 
723  template <unsigned n, typename S>
724  inline
725  typename rgb<n>::interop
726  operator*(const mln::value::scalar_<S>& s, const rgb<n>& lhs)
727  {
728  typename rgb<n>::interop tmp(s.to_equiv() * lhs.to_interop());
729  return tmp;
730  }
731 
732  template <unsigned n, typename S>
733  inline
734  typename rgb<n>::interop
735  operator/(const rgb<n>& lhs, const mln::value::scalar_<S>& s)
736  {
737  typename rgb<n>::interop tmp(lhs.to_interop() / s.to_equiv());
738  return tmp;
739  }
740 
741  template <unsigned n>
742  inline
743  std::ostream& operator<<(std::ostream& ostr, const rgb<n>& v)
744  {
745  return ostr << '(' << debug::format(v.red())
746  << ',' << debug::format(v.green())
747  << ',' << debug::format(v.blue())
748  << ')';
749  }
750 
751  template <unsigned n>
752  inline
753  std::istream& operator>>(std::istream& istr, rgb<n>& c)
754  {
755  return istr >> c.red() >> c.green() >> c.blue();
756  }
757 
758  } // end of namespace mln::value
759 
760 
761  namespace convert
762  {
763 
764  namespace over_load
765  {
766 
767  // algebra::vec -> rgb.
768  template <typename T, unsigned m>
769  inline
770  void
771  from_to_(const algebra::vec<3,T>& from, value::rgb<m>& to)
772  {
773  algebra::vec<3, unsigned> tmp;
774  for (unsigned i = 0; i < 3; ++i)
775  tmp[i] = static_cast<unsigned>(from[i]); // FIXME: Use from_to_ instead of cast.
776 
777  to = value::rgb<m>(tmp);
778  }
779 
780  // bool -> rgb.
781  template <unsigned m>
782  void
783  from_to_(bool from, value::rgb<m>& to)
784  {
785  static literal::white_t* white_ = 0;
786  static literal::black_t* black_ = 0;
787  // We do not use literal::white (the object) so that we
788  // do not introduce any coupling with the file where
789  // literals are defined.
790  if (from)
791  to = *white_;
792  else
793  to = *black_;
794  }
795 
796  template <unsigned m>
797  void
798  from_to_(const value::int_u<m>& from, value::rgb<m>& to)
799  {
800  to = value::rgb<m>(from, from, from);
801  }
802 
803  template <typename H, typename S, typename L>
804  void
805  from_to_(const value::hsl_<H,S,L>& from, value::rgb<8>& to)
806  {
807  to = fun::v2v::f_hsl_to_rgb_3x8(from);
808  }
809 
810 // template <typename H, typename S, typename L>
811 // void
812 // from_to_(const value::hsl_<H,S,L>& from, value::rgb<16>& to)
813 // {
814 // to = fun::v2v::f_hsl_to_rgb_3x16(from);
815 // }
816 
817  template <unsigned m>
818  void
819  from_to_(const value::rgb<m>& from, bool& to)
820  {
821  to = (from.red() != 0 && from.green() != 0 && from.blue() != 0);
822  }
823 
824  } // end of namespace mln::convert::over_load
825 
826  } // end of namespace mln::convert
827 
828 } // end of namespace mln
829 
830 # endif // ! MLN_INCLUDE_ONLY
831 
832 
833 #endif // ! MLN_VALUE_RGB_HH