Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <basegfx/numeric/ftools.hxx>
21 : #include <basegfx/color/bcolor.hxx>
22 : #include <basegfx/color/bcolortools.hxx>
23 :
24 : //////////////////////////////////////////////////////////////////////////////
25 :
26 : namespace basegfx { namespace tools
27 : {
28 34 : BColor rgb2hsl(const BColor& rRGBColor)
29 : {
30 34 : const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue();
31 34 : const double minVal = ::std::min( ::std::min( r, g ), b );
32 34 : const double maxVal = ::std::max( ::std::max( r, g ), b );
33 34 : const double d = maxVal - minVal;
34 :
35 34 : double h=0, s=0, l=0;
36 :
37 34 : l = (maxVal + minVal) / 2.0;
38 :
39 34 : if( ::basegfx::fTools::equalZero(d) )
40 : {
41 6 : s = h = 0; // hue undefined (achromatic case)
42 : }
43 : else
44 : {
45 : s = l > 0.5 ? d/(2.0-maxVal-minVal) :
46 28 : d/(maxVal + minVal);
47 :
48 28 : if( r == maxVal )
49 10 : h = (g - b)/d;
50 18 : else if( g == maxVal )
51 6 : h = 2.0 + (b - r)/d;
52 : else
53 12 : h = 4.0 + (r - g)/d;
54 :
55 28 : h *= 60.0;
56 :
57 28 : if( h < 0.0 )
58 3 : h += 360.0;
59 : }
60 :
61 34 : return BColor(h,s,l);
62 : }
63 :
64 42 : static inline double hsl2rgbHelper( double nValue1, double nValue2, double nHue )
65 : {
66 : // clamp hue to [0,360]
67 42 : nHue = fmod( nHue, 360.0 );
68 :
69 : // cope with wrap-arounds
70 42 : if( nHue < 0.0 )
71 2 : nHue += 360.0;
72 :
73 42 : if( nHue < 60.0 )
74 11 : return nValue1 + (nValue2 - nValue1)*nHue/60.0;
75 31 : else if( nHue < 180.0 )
76 14 : return nValue2;
77 17 : else if( nHue < 240.0 )
78 3 : return nValue1 + (nValue2 - nValue1)*(240.0 - nHue)/60.0;
79 : else
80 14 : return nValue1;
81 : }
82 :
83 16 : BColor hsl2rgb(const BColor& rHSLColor)
84 : {
85 16 : const double h=rHSLColor.getRed(), s=rHSLColor.getGreen(), l=rHSLColor.getBlue();
86 :
87 16 : if( fTools::equalZero(s) )
88 2 : return BColor(l, l, l ); // achromatic case
89 :
90 14 : const double nVal1( l <= 0.5 ? l*(1.0 + s) : l + s - l*s );
91 14 : const double nVal2( 2.0*l - nVal1 );
92 :
93 : return BColor(
94 : hsl2rgbHelper(nVal2,
95 : nVal1,
96 : h + 120.0),
97 : hsl2rgbHelper(nVal2,
98 : nVal1,
99 : h),
100 : hsl2rgbHelper(nVal2,
101 : nVal1,
102 14 : h - 120.0) );
103 : }
104 :
105 25 : BColor rgb2hsv(const BColor& rRGBColor)
106 : {
107 25 : const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue();
108 25 : const double maxVal = std::max(std::max(r,g),b);
109 25 : const double minVal = std::min(std::min(r,g),b);
110 25 : const double delta = maxVal-minVal;
111 :
112 25 : double h=0, s=0, v=0;
113 :
114 25 : v = maxVal;
115 25 : if( fTools::equalZero(v) )
116 2 : s = 0;
117 : else
118 23 : s = delta / v;
119 :
120 25 : if( !fTools::equalZero(s) )
121 : {
122 19 : if( maxVal == r )
123 : {
124 10 : h = (g - b) / delta;
125 : }
126 9 : else if( maxVal == g )
127 : {
128 6 : h = 2.0 + (b - r) / delta;
129 : }
130 : else
131 : {
132 3 : h = 4.0 + (r - g) / delta;
133 : }
134 :
135 19 : h *= 60.0;
136 :
137 19 : if( h < 0 )
138 3 : h += 360;
139 : }
140 :
141 25 : return BColor(h,s,v);
142 : }
143 :
144 8 : BColor hsv2rgb(const BColor& rHSVColor)
145 : {
146 8 : double h=rHSVColor.getRed();
147 8 : const double s=rHSVColor.getGreen(), v=rHSVColor.getBlue();
148 :
149 8 : if( fTools::equalZero(s) )
150 : {
151 : // achromatic case: no hue.
152 2 : return BColor(v,v,v);
153 : }
154 : else
155 : {
156 6 : if( fTools::equal(h,360) )
157 0 : h = 0; // 360 degrees is equivalent to 0 degrees
158 :
159 6 : h /= 60.0;
160 6 : const sal_Int32 intval = static_cast< sal_Int32 >( h );
161 6 : const double f = h - intval;
162 6 : const double p = v*(1.0-s);
163 6 : const double q = v*(1.0-(s*f));
164 6 : const double t = v*(1.0-(s*(1.0-f)));
165 :
166 : /* which hue area? */
167 6 : switch( intval )
168 : {
169 : case 0:
170 1 : return BColor(v,t,p);
171 :
172 : case 1:
173 1 : return BColor(q,v,p);
174 :
175 : case 2:
176 1 : return BColor(p,v,t);
177 :
178 : case 3:
179 1 : return BColor(p,q,v);
180 :
181 : case 4:
182 1 : return BColor(t,p,v);
183 :
184 : case 5:
185 1 : return BColor(v,p,q);
186 :
187 : default:
188 : // hue overflow
189 0 : return BColor();
190 : }
191 : }
192 : }
193 :
194 8 : BColor rgb2ciexyz( const BColor& rRGBColor )
195 : {
196 : // from Poynton color faq, and SMPTE RP 177-1993, Derivation
197 : // of Basic Television Color Equations
198 8 : const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue();
199 : return BColor(
200 : 0.412453*r + 0.35758*g + 0.180423*b,
201 : 0.212671*r + 0.71516*g + 0.072169*b,
202 8 : 0.019334*r + 0.119193*g + 0.950227*b);
203 : }
204 :
205 : } } // end of namespace basegfx
206 :
207 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|