1 /* === S Y N F I G ========================================================= */
2 /*! \file color.cpp
3 ** \brief Color Class implementation
4 **
5 ** $Id$
6 **
7 ** \legal
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
10 ** Copyright (c) 2012-2013 Carlos López
11 ** Copyright (c) 2015 Diego Barrios Romero
12 **
13 ** This package is free software; you can redistribute it and/or
14 ** modify it under the terms of the GNU General Public License as
15 ** published by the Free Software Foundation; either version 2 of
16 ** the License, or (at your option) any later version.
17 **
18 ** This package is distributed in the hope that it will be useful,
19 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 ** General Public License for more details.
22 ** \endlegal
23 */
24 /* ========================================================================= */
25
26 /* === H E A D E R S ======================================================= */
27
28 #ifdef USING_PCH
29 # include "pch.h"
30 #else
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34
35 #include <ETL/angle>
36 #include "color.h"
37 #include <cstdio>
38 #include <sstream>
39 #include <iostream>
40 #include <iomanip>
41
42 #include "colorblendingfunctions.h"
43
44 #endif
45
46 using namespace synfig;
47 using namespace etl;
48 using namespace std;
49
50 #define COLOR_EPSILON (0.000001f)
51
52 const Color::value_type Color::ceil=1;
53 const Color::value_type Color::floor=0;
54
55 /* === M E T H O D S ======================================================= */
56
57 ColorReal
hex2real(String s)58 Color::hex2real(String s)
59 {
60 std::istringstream i(s);
61 int n;
62 i.fill('0');
63 if (!(i >> hex >> n))
64 throw String("bad conversion from hex string \"") + s + String("\"");
65 return n / 255.0f;
66 }
67
68 const String
real2hex(ColorReal c)69 Color::real2hex(ColorReal c)
70 {
71 std::ostringstream o;
72 o.width(2);
73 o.fill('0');
74 if (c<0) c = 0;
75 if (c>1) c = 1;
76 o << hex << int(c*255.0f);
77 return o.str();
78 }
79
80 void
set_hex(String & str)81 Color::set_hex(String& str)
82 {
83 value_type r, g, b;
84 String hex;
85
86 // use just the hex characters
87 for (String::const_iterator iter = str.begin(); iter != str.end(); iter++)
88 if (isxdigit(*iter))
89 hex.push_back(*iter);
90
91 try
92 {
93 if (hex.size() == 1)
94 {
95 r = hex2real(hex.substr(0,1)+hex.substr(0,1));
96 r_ = g_ = b_ = r;
97 }
98 else if (hex.size() == 3)
99 {
100 r = hex2real(hex.substr(0,1)+hex.substr(0,1));
101 g = hex2real(hex.substr(1,1)+hex.substr(1,1));
102 b = hex2real(hex.substr(2,1)+hex.substr(2,1));
103 r_ = r; g_ = g; b_ = b;
104 }
105 else if (hex.size() == 6)
106 {
107 r = hex2real(hex.substr(0,2));
108 g = hex2real(hex.substr(2,2));
109 b = hex2real(hex.substr(4,2));
110 r_ = r; g_ = g; b_ = b;
111 }
112 }
113 catch (string s)
114 {
115 printf("caught <%s>\n", s.c_str());
116 return;
117 }
118 }
119
120 const String
get_string(void) const121 Color::get_string(void)const
122 {
123 std::ostringstream o;
124 o << std::fixed << std::setprecision(3) << "#" << get_hex().c_str() << " : " << std::setw(6) << a_;
125 return String(o.str().c_str());
126 }
127
128 Color
clamped_negative() const129 Color::clamped_negative()const
130 {
131 Color ret=*this;
132
133 if(ret.a_==0)
134 return alpha();
135
136 if(ret.a_<0)
137 ret=-ret;
138
139 if(ret.r_<0)
140 {
141 ret.g_-=ret.r_;
142 ret.b_-=ret.r_;
143 ret.r_=0.0f;
144 }
145 if(ret.g_<0)
146 {
147 ret.r_-=ret.g_;
148 ret.b_-=ret.g_;
149 ret.g_=0.0f;
150 }
151 if(ret.b_<0)
152 {
153 ret.r_-=ret.b_;
154 ret.g_-=ret.b_;
155 ret.b_=0.0f;
156 }
157
158 if(ret.r_>1) ret.r_=1;
159 if(ret.g_>1) ret.g_=1;
160 if(ret.b_>1) ret.b_=1;
161 if(ret.a_>1) ret.a_=1;
162
163 if(std::isnan(ret.get_r())) ret.r_=0.5;
164 if(std::isnan(ret.get_g())) ret.g_=0.5;
165 if(std::isnan(ret.get_b())) ret.b_=0.5;
166 if(std::isnan(ret.get_a())) ret.a_=1;
167
168 /*
169 if(ret.r_>1) { ret.g_/=ret.r_; ret.b_/=ret.r_; ret.r_=1; }
170 if(ret.g_>1) { ret.r_/=ret.g_; ret.b_/=ret.g_; ret.g_=1; }
171 if(ret.b_>1) { ret.g_/=ret.b_; ret.r_/=ret.b_; ret.b_=1; }
172 if(ret.a_>1) ret.a_=1;
173 */
174
175 return ret;
176 }
177
178 Color
clamped() const179 Color::clamped()const
180 {
181 Color ret(*this);
182 if(ret.get_r()<0)
183 ret.set_r(0);
184 if(ret.get_g()<0)
185 ret.set_g(0);
186 if(ret.get_b()<0)
187 ret.set_b(0);
188 if(ret.get_a()<0)
189 ret.set_a(0);
190
191 if(ret.r_>1) ret.r_=1;
192 if(ret.g_>1) ret.g_=1;
193 if(ret.b_>1) ret.b_=1;
194 if(ret.a_>1) ret.a_=1;
195
196 if(std::isnan(ret.get_r())) ret.r_=0.5;
197 if(std::isnan(ret.get_g())) ret.g_=0.5;
198 if(std::isnan(ret.get_b())) ret.b_=0.5;
199 if(std::isnan(ret.get_a())) ret.a_=1;
200
201 return(ret);
202 }
203
204
205 Color
blend(Color a,Color b,float amount,Color::BlendMethod type)206 Color::blend(Color a, Color b,float amount, Color::BlendMethod type)
207 {
208 // No matter what blend method is being used,
209 // if the amount is equal to zero, then only B
210 // will shine through
211 if(fabsf(amount)<=COLOR_EPSILON)return b;
212
213 assert(type<BLEND_END);
214
215 const static blendfunc vtable[BLEND_END]=
216 {
217 // WARNING: any change here must be coordinated with
218 // other specializations of the functions, for example
219 // for CairoColor
220 blendfunc_COMPOSITE<Color>, // 0
221 blendfunc_STRAIGHT<Color>,
222 blendfunc_BRIGHTEN<Color>,
223 blendfunc_DARKEN<Color>,
224 blendfunc_ADD<Color>,
225 blendfunc_SUBTRACT<Color>, // 5
226 blendfunc_MULTIPLY<Color>,
227 blendfunc_DIVIDE<Color>,
228 blendfunc_COLOR<Color>,
229 blendfunc_HUE<Color>,
230 blendfunc_SATURATION<Color>, // 10
231 blendfunc_LUMINANCE<Color>,
232 blendfunc_BEHIND<Color>,
233 blendfunc_ONTO<Color>,
234 blendfunc_ALPHA_BRIGHTEN<Color>,
235 blendfunc_ALPHA_DARKEN<Color>, // 15
236 blendfunc_SCREEN<Color>,
237 blendfunc_HARD_LIGHT<Color>,
238 blendfunc_DIFFERENCE<Color>,
239 blendfunc_ALPHA_OVER<Color>,
240 blendfunc_OVERLAY<Color>, // 20
241 blendfunc_STRAIGHT_ONTO<Color>,
242 };
243
244 return vtable[type](a,b,amount);
245 }
246
247