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