1 /* hsv2rgb.i 2 * conversions among RGB, HSV, HSL, CMYK color representations 3 * 4 * See Wikipedia article "HSL and HSV" 5 */ 6 /* Copyright (c) 2013, David H. Munro. 7 * All rights reserved. 8 * This file is part of yorick (http://yorick.sourceforge.net). 9 * Read the accompanying LICENSE file for details. 10 */ 11 12 func rgb2hsv(r, g, b, cmax=) 13 /* DOCUMENT hsv = rgb2hsv([r, g, b]) 14 * or hsv = rgb2hsv(r, g, b) 15 * Returns hue-saturation-value given red-green-blue. 16 * Return value has same dimensions as input (in first form). 17 * If input rgb are real, they are assumed normalized to lie in [0.,1.]. 18 * If input are integers, they are assumed to lie in [0,255]. 19 * You can specify a different maximum color value using the cmax= 20 * keyword. 21 * Note that the HSV and HSL systems share a common definition of 22 * hue H, but that saturation S is a very different thing. 23 * SEE ALSO: rgb2hsl, hsv2rgb, hsl2rgb, rgb2cmyk, cmyk2rgb, rgb2hsi 24 */ 25 { 26 local rgb, V, m, C, L, H; 27 _2hs; 28 S = C / max(V, 1.e-20); /* hsv saturation */ 29 return [H, S, V]; 30 } 31 32 func rgb2hsl(r, g, b, cmax=) 33 /* DOCUMENT hsl = rgb2hsl([r, g, b]) 34 * or hsl = rgb2hsl(r, g, b) 35 * Returns hue-saturation-lightness given red-green-blue. 36 * Return value has same dimensions as input (in first form). 37 * If input rgb are real, they are assumed normalized to lie in [0.,1.]. 38 * If input are integers, they are assumed to lie in [0,255]. 39 * You can specify a different maximum color value using the cmax= 40 * keyword. 41 * Note that the HSV and HSL systems share a common definition of 42 * hue H, but that saturation S is a very different thing. 43 * SEE ALSO: rgb2hsv, hsv2rgb, hsl2rgb, rgb2cmyk, cmyk2rgb, rgb2hsi 44 */ 45 { 46 local rgb, V, m, C, L, H; 47 _2hs; 48 S = C / max(1.-abs(2.*L-1.), 1.e-20); /* hsl saturation */ 49 return [H, S, L]; 50 } 51 52 func hsv2rgb(H, S, V, cmax=) 53 /* DOCUMENT rgb = hsv2rgb([h, s, v]) 54 * or rgb = hsv2rgb(h, s, v) 55 * Returns red-green-blue given hue-saturation-value. 56 * Return value has same dimensions as input (in first form). 57 * Output rgb are type char by default, with range [0,255]. 58 * You can specify a different maximum color value using the cmax= 59 * keyword. With cmax=1, return value will be type double, with 60 * range [0.,1.]; otherwise, the return value will be double if cmax 61 * is real, char if cmax is an integer <=255, otherwise long. 62 * Note that the HSV and HSL systems share a common definition of 63 * hue H, but that saturation S is a very different thing. 64 * SEE ALSO: hsl2rgb, rgb2hsv, rgb2hsl, rgb2cmyk, cmyk2rgb, rgb2hsi 65 */ 66 { 67 if (is_void(S)) { 68 S = H(..,2); 69 V = H(..,3); 70 H = H(..,1); 71 } 72 C = V*S; 73 return _2rgb(H, C, V-C, cmax=cmax); 74 } 75 76 func hsl2rgb(H, S, L, cmax=) 77 /* DOCUMENT rgb = hsl2rgb([h, s, l]) 78 * or rgb = hsl2rgb(h, s, l) 79 * Returns red-green-blue given hue-saturation-lightness. 80 * Return value has same dimensions as input (in first form). 81 * Output rgb are type char by default, with range [0,255]. 82 * You can specify a different maximum color value using the cmax= 83 * keyword. With cmax=1, return value will be type double, with 84 * range [0.,1.]; otherwise, the return value will be double if cmax 85 * is real, char if cmax is an integer <=255, otherwise long. 86 * Note that the HSV and HSL systems share a common definition of 87 * hue H, but that saturation S is a very different thing. 88 * SEE ALSO: hsv2rgb, rgb2hsl, rgb2hsv, rgb2cmyk, cmyk2rgb, rgb2hsi 89 */ 90 { 91 if (is_void(S)) { 92 S = H(..,2); 93 L = H(..,3); 94 H = H(..,1); 95 } 96 C = (1.-abs(2.*L-1.)) * S; 97 return _2rgb(H, C, L-0.5*C, cmax=cmax); 98 } 99 100 func _2rgb(H, C, m, cmax=) 101 { 102 H *= 1./60.; 103 H -= 6.*floor(H/6.); /* permit illegal hue >360 or <0 */ 104 n = array(0, dimsof(H)); 105 nc = numberof(H); 106 n(*) = indgen(nc); 107 rgb = array(0., dimsof(H), 3); 108 i = digitize(H, indgen(5)) % 6; 109 j = i / 2; 110 i = (j + [2,1]((i&1)+1)) % 3; 111 rgb(n+j*nc) = C; 112 rgb(n+i*nc) = C * (1. - abs(H%2. - 1.)); 113 rgb += m; 114 if (is_void(cmax)) cmax = 255; 115 if (cmax == 1) cmax = 1.0; 116 rgb *= cmax; 117 if (structof(cmax+0) == long) { 118 rgb = long(rgb + 0.5); 119 if (max(cmax) < 256) rgb = char(rgb); 120 } 121 return rgb; 122 } 123 124 func _2hs 125 { 126 extern rgb, V, m, C, L, H; 127 rgb = is_void(g)? r : [r, g, b]; 128 if (is_void(cmax)) cmax = (structof(r+0)==long)? 255. : 1.0; 129 rgb *= 1./cmax; 130 r = rgb(..,1); 131 g = rgb(..,2); 132 b = rgb(..,3); 133 V = rgb(..,max); /* value */ 134 m = rgb(..,min); 135 if (max(V) > 1.) error, "need explicit cmax= specification"; 136 if (min(m) < 0.) error, "rgb color component less than zero"; 137 C = V - m; /* chroma */ 138 L = 0.5*(V+m); /* lightness */ 139 n = array(0, dimsof(r)); 140 nr = numberof(r); 141 n(*) = indgen(nr); 142 i = (V == rgb)(..,mxx) - 1; 143 H = ((rgb(n+((i+1)%3)*nr) - rgb(n+((i+2)%3)*nr))/max(C,1.e-20) + 2.*i+6.)%6.; 144 H *= 60.; /* hue */ 145 } 146 147 func rgb2cmyk(r, g, b, cmax=) 148 /* DOCUMENT cmyk = rgb2cmyk([r, g, b]) 149 * or cmyk = rgb2cmyk(r, g, b) 150 * Returns cyan-magenta-yellow-black given red-green-blue. The 151 * returned [c, m, y, k] are normalized to lie in [0., 1.]. 152 * Return value has same dimensions as input (in first form). 153 * If input rgb are real, they are assumed normalized to lie in [0.,1.]. 154 * If input are integers, they are assumed to lie in [0,255]. 155 * You can specify a different maximum color value using the cmax= 156 * keyword. 157 * In this simple conversion scheme, the complement of the largest 158 * component of [r,g,b] will always be 0.0. This is the choice with 159 * the largest possible k component. 160 * SEE ALSO: cmyk2rgb, rgb2hsv, hsv2rgb, rgb2hsl, hsl2rgb, rgb2hsi 161 */ 162 { 163 rgb = is_void(g)? r : [r, g, b]; 164 if (is_void(cmax)) cmax = (structof(r+0)==long)? 255. : 1.0; 165 rgb *= 1./cmax; 166 V = rgb(..,max); /* value */ 167 zero = double(!V); 168 rgb *= (1. + zero) / (V + zero); 169 c = 1. - rgb(..,1); 170 m = 1. - rgb(..,2); 171 y = 1. - rgb(..,3); 172 k = 1. - V; 173 return [c, m, y, k]; 174 } 175 176 func cmyk2rgb(c, m, y, k, cmax=) 177 /* DOCUMENT rgb = cmyk2rgb([c, m, y, k]) 178 * or rgb = cmyk2rgb(c, m, y, k) 179 * Returns red-green-blue given cyan-magenta-yellow-black. The 180 * C, M, Y, K values must be between 0.0 and 1.0 inclusive. 181 * Return value has same dimensions as input (in first form). 182 * Output rgb are type char by default, with range [0,255]. 183 * You can specify a different maximum color value using the cmax= 184 * keyword. With cmax=1, return value will be type double, with 185 * range [0.,1.]; otherwise, the return value will be double if cmax 186 * is real, char if cmax is an integer <=255, otherwise long. 187 * SEE ALSO: rgb2cmyk, hsv2rgb, rgb2hsv, hsl2rgb, rgb2hsl, rgb2hsi 188 */ 189 { 190 rgb = 1. - (is_void(m)? c : [c, m, y, k]); 191 rgb = rgb(,1:3) * rgb(4); 192 if (is_void(cmax)) cmax = 255; 193 if (cmax == 1) cmax = 1.0; 194 rgb *= cmax; 195 if (structof(cmax+0) == long) { 196 rgb = long(rgb + 0.5); 197 if (max(cmax) < 256) rgb = char(rgb); 198 } 199 return rgb; 200 } 201 202 /* ------------------------------------------------------------------------ */ 203