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 #include <rtl/math.hxx> 24 25 namespace basegfx::utils 26 { rgb2hsl(const BColor & rRGBColor)27 BColor rgb2hsl(const BColor& rRGBColor) 28 { 29 const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue(); 30 const double minVal = std::min( std::min( r, g ), b ); 31 const double maxVal = std::max( std::max( r, g ), b ); 32 const double d = maxVal - minVal; 33 34 double h=0, s=0, l=0; 35 36 l = (maxVal + minVal) / 2.0; 37 38 if( ::basegfx::fTools::equalZero(d) ) 39 { 40 s = h = 0; // hue undefined (achromatic case) 41 } 42 else 43 { 44 s = l > 0.5 ? d/(2.0-maxVal-minVal) : 45 d/(maxVal + minVal); 46 47 if( rtl::math::approxEqual(r, maxVal) ) 48 h = (g - b)/d; 49 else if( rtl::math::approxEqual(g, maxVal) ) 50 h = 2.0 + (b - r)/d; 51 else 52 h = 4.0 + (r - g)/d; 53 54 h *= 60.0; 55 56 if( h < 0.0 ) 57 h += 360.0; 58 } 59 60 return BColor(h,s,l); 61 } 62 hsl2rgbHelper(double nValue1,double nValue2,double nHue)63 static double hsl2rgbHelper( double nValue1, double nValue2, double nHue ) 64 { 65 // clamp hue to [0,360] 66 nHue = fmod( nHue, 360.0 ); 67 68 // cope with wrap-arounds 69 if( nHue < 0.0 ) 70 nHue += 360.0; 71 72 if( nHue < 60.0 ) 73 return nValue1 + (nValue2 - nValue1)*nHue/60.0; 74 else if( nHue < 180.0 ) 75 return nValue2; 76 else if( nHue < 240.0 ) 77 return nValue1 + (nValue2 - nValue1)*(240.0 - nHue)/60.0; 78 else 79 return nValue1; 80 } 81 hsl2rgb(const BColor & rHSLColor)82 BColor hsl2rgb(const BColor& rHSLColor) 83 { 84 const double h=rHSLColor.getRed(), s=rHSLColor.getGreen(), l=rHSLColor.getBlue(); 85 86 if( fTools::equalZero(s) ) 87 return BColor(l, l, l ); // achromatic case 88 89 const double nVal1( l <= 0.5 ? l*(1.0 + s) : l + s - l*s ); 90 const double nVal2( 2.0*l - nVal1 ); 91 92 return BColor( 93 hsl2rgbHelper(nVal2, 94 nVal1, 95 h + 120.0), 96 hsl2rgbHelper(nVal2, 97 nVal1, 98 h), 99 hsl2rgbHelper(nVal2, 100 nVal1, 101 h - 120.0) ); 102 } 103 rgb2hsv(const BColor & rRGBColor)104 BColor rgb2hsv(const BColor& rRGBColor) 105 { 106 const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue(); 107 const double maxVal = std::max(std::max(r,g),b); 108 const double minVal = std::min(std::min(r,g),b); 109 const double delta = maxVal-minVal; 110 111 double h=0, s=0, v=0; 112 113 v = maxVal; 114 if( fTools::equalZero(v) ) 115 s = 0; 116 else 117 s = delta / v; 118 119 if( !fTools::equalZero(s) ) 120 { 121 if( rtl::math::approxEqual(maxVal, r) ) 122 { 123 h = (g - b) / delta; 124 } 125 else if( rtl::math::approxEqual(maxVal, g) ) 126 { 127 h = 2.0 + (b - r) / delta; 128 } 129 else 130 { 131 h = 4.0 + (r - g) / delta; 132 } 133 134 h *= 60.0; 135 136 if( h < 0 ) 137 h += 360; 138 } 139 140 return BColor(h,s,v); 141 } 142 hsv2rgb(const BColor & rHSVColor)143 BColor hsv2rgb(const BColor& rHSVColor) 144 { 145 double h=rHSVColor.getRed(); 146 const double s=rHSVColor.getGreen(), v=rHSVColor.getBlue(); 147 148 if( fTools::equalZero(s) ) 149 { 150 // achromatic case: no hue. 151 return BColor(v,v,v); 152 } 153 else 154 { 155 if( fTools::equal(h,360) ) 156 h = 0; // 360 degrees is equivalent to 0 degrees 157 158 h /= 60.0; 159 const sal_Int32 intval = static_cast< sal_Int32 >( h ); 160 const double f = h - intval; 161 const double p = v*(1.0-s); 162 const double q = v*(1.0-(s*f)); 163 const double t = v*(1.0-(s*(1.0-f))); 164 165 /* which hue area? */ 166 switch( intval ) 167 { 168 case 0: 169 return BColor(v,t,p); 170 171 case 1: 172 return BColor(q,v,p); 173 174 case 2: 175 return BColor(p,v,t); 176 177 case 3: 178 return BColor(p,q,v); 179 180 case 4: 181 return BColor(t,p,v); 182 183 case 5: 184 return BColor(v,p,q); 185 186 default: 187 // hue overflow 188 return BColor(); 189 } 190 } 191 } 192 193 } // end of namespace 194 195 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 196