javascript - convertir Hsl a rgb y hexadecimal
jquery colors (6)
HSL a RGB:
/**
* Converts an HSL color value to RGB. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
* Assumes h, s, and l are contained in the set [0, 1] and
* returns r, g, and b in the set [0, 255].
*
* @param {number} h The hue
* @param {number} s The saturation
* @param {number} l The lightness
* @return {Array} The RGB representation
*/
function hslToRgb(h, s, l){
var r, g, b;
if(s == 0){
r = g = b = l; // achromatic
}else{
var hue2rgb = function hue2rgb(p, q, t){
if(t < 0) t += 1;
if(t > 1) t -= 1;
if(t < 1/6) return p + (q - p) * 6 * t;
if(t < 1/2) return q;
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
Puede encontrar más información aquí:
conversión de color HSL a RGB
Necesito un convertidor de color para convertir de hsl a rgb y valor hexadecimal.
Voy a hacer algo similar a
esto
.
Estoy usando jquery y jquery ui range slider para esto.
Aquí está mi código:
$(function() {
$( "#hsl_hue_range" ).slider({
min: 0,
max: 100,
value: 0,
range: false,
animate:"slow",
orientation: "horizontal",
slide: function( event, ui ) {
var hsl_hue = ui.value;
}
});
});
$(function() {
$( "#hsl_saturation_range" ).slider({
min: 0,
max: 100,
value: 0,
range: false,
animate:"slow",
orientation: "horizontal",
slide: function( event, ui ) {
var hsl_saturation = ui.value;
}
});
});
$(function() {
$( "#hsl_light_range" ).slider({
min: 0,
max: 100,
value: 0,
range: false,
animate:"slow",
orientation: "horizontal",
slide: function( event, ui ) {
var hsl_light = ui.value;
}
});
});
Quiero la solución como esta:
la entrada al convertidor puede ser dada por las variables.
como
hsl_hue
hsl_saturation
hsl_light
.
¿Hay alguna forma de hacer esto?
Si no, ¿qué puedo hacer?
He creado una pequeña biblioteca que puede convertir fácilmente los colores.
Este es mi método HSL a RGB, que utiliza algunos otros métodos de utilidad de la biblioteca:
Color.hslToRgb = function(hsl, formatted) {
var a, b, g, h, l, p, q, r, ref, s;
if (isString(hsl)) {
if (!hsl.match(Color.HSL_REGEX)) {
return;
}
ref = hsl.match(/hsla?/((.+?)/)/)[1].split('','').map(function(value) {
value.trim();
return parseFloat(value);
}), h = ref[0], s = ref[1], l = ref[2], a = ref[3];
} else if ((isObject(hsl)) && (hasKeys(hsl, [''h'', ''s'', ''l'']))) {
h = hsl.h, s = hsl.s, l = hsl.l, a = hsl.a;
} else {
return;
}
h /= 360;
s /= 100;
l /= 100;
if (s === 0) {
r = g = b = l;
} else {
q = l < 0.5 ? l * (1 + s) : l + s - l * s;
p = 2 * l - q;
r = Color.hueToRgb(p, q, h + 1 / 3);
g = Color.hueToRgb(p, q, h);
b = Color.hueToRgb(p, q, h - 1 / 3);
}
return getRgb(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), a, formatted);
};
Si no desea usar npm, la lib también se puede encontrar en GitHub .
Otra forma de resolver este problema es aprovechar la capacidad
window.getComputedStyle
de los navegadores modernos:
-
Cree un elemento en la página (se puede ocultar, por ejemplo, con
display:none
, pero parece que suprime la salida del valor de opacidad / "A") -
Establezca una propiedad con valor de color de ese elemento utilizando la representación que elija, por ejemplo,
e.style.color = ''hsla(100, 50%, 75%, 0.8)'';
(o incluso colores nombrados como''rebeccapurple''
) -
Lea el valor nuevamente usando
window.getComputedStyle(e).color
. Será una cadena de la formargb(r,g,b)
orgba(r,g,b,a)
.
Pruebe esto ( wiki , analysis errores, más: rgb2hsl , hsv2rgb rgb2hsv y hsl2hsv )
// input: h in [0,360] and s,v in [0,1] - output: r,g,b in [0,1]
function hsl2rgb(h,s,l)
{
let a=s*Math.min(l,1-l);
let f= (n,k=(n+h/30)%12) => l - a*Math.max(Math.min(k-3,9-k,1),-1);
return [f(0),f(8),f(4)];
}
Para calcular hsl2hex use
rgb2hex(...hsl2rgb(30,1,0.5))
.
Para convertir cadenas de formato, por ejemplo,
rgb(255, 255, 255)
a hexadecimal, use
rgbStrToHex
(que maneja el caso de cadena vacía)
// r,g,b are in [0-1], result e.g. #0812fa.
let rgb2hex = (r,g,b) => "#"+[r,g,b].map(x=>Math.round(x*255).toString(16).padStart(2,0)).join('''');
// rgbStr e.g. "rgb(255, 255,255)", result e.g. #ffffff.
let rgbStrToHex = (rgbStr) => rgbStr && ''#''+rgbStr.slice(4,-1).split('', '').map(x => (+x).toString(16).padStart(2, ''0'')).join('''');
// oneliner version
let hsl2rgb = (h,s,l, a=s*Math.min(l,1-l), f= (n,k=(n+h/30)%12) => l - a*Math.max(Math.min(k-3,9-k,1),-1)) => [f(0),f(8),f(4)];
let rgb2hex = (r,g,b) => "#" + [r,g,b].map(x=>Math.round(x*255).toString(16).padStart(2,0) ).join('''');
let rgbStrToHex = (rgbStr) => rgbStr && ''#''+rgbStr.slice(4,-1).split('','').map(x => (+x).toString(16).padStart(2, ''0'')).join('''');
console.log(`hsl: (30,0.2,0.3) --> rgb: (${hsl2rgb(30,0.2,0.3)}) --> hex: ${rgb2hex(...hsl2rgb(30,0.2,0.3))}`);
console.log(`str: "rgb(255,100, 123)" --> hex: ${rgbStrToHex("rgb(255,100, 123)")}`)
// ---------------
// UX
// ---------------
rgb= [0,0,0];
hs= [0,0,0];
let $ = x => document.querySelector(x);
function changeRGB(i,e) {
rgb[i]=e.target.value/255;
hs = rgb2hsl(...rgb);
refresh();
}
function changeHS(i,e) {
hs[i]=e.target.value/(i?255:1);
rgb= hsl2rgb(...hs);
refresh();
}
function refresh() {
rr = rgb.map(x=>x*255|0).join('', '')
hh = rgb2hex(...rgb);
tr = `RGB: ${rr}`
th = `HSL: ${hs.map((x,i)=>i? (x*100).toFixed(2)+''%'':x|0).join('', '')}`
thh= `HEX: ${hh}`
$(''.box'').style.backgroundColor=`rgb(${rr})`;
$(''.infoRGB'').innerHTML=`${tr}`;
$(''.infoHS'').innerHTML =`${th}/n${thh}`;
$(''#r'').value=rgb[0]*255;
$(''#g'').value=rgb[1]*255;
$(''#b'').value=rgb[2]*255;
$(''#h'').value=hs[0];
$(''#s'').value=hs[1]*255;
$(''#l'').value=hs[2]*255;
}
function rgb2hsl(r,g,b) {
let a=Math.max(r,g,b), n=a-Math.min(r,g,b), f=(1-Math.abs(a+a-n-1));
let h= n && ((a==r) ? (g-b)/n : ((a==g) ? 2+(b-r)/n : 4+(r-g)/n));
return [60*(h<0?h+6:h), f ? n/f : 0, (a+a-n)/2];
}
refresh();
.box {
width: 50px;
height: 50px;
margin: 20px;
}
body {
display: flex;
}
<div>
<input id="r" type="range" min="0" max="255" oninput="changeRGB(0,event)">R<br>
<input id="g" type="range" min="0" max="255" oninput="changeRGB(1,event)">G<br>
<input id="b" type="range" min="0" max="255" oninput="changeRGB(2,event)">B<br>
<pre class="infoRGB"></pre>
</div>
<div>
<div class="box hsl"></div>
</div>
<div>
<input id="h" type="range" min="0" max="360" oninput="changeHS(0,event)">H<br>
<input id="s" type="range" min="0" max="255" oninput="changeHS(1,event)">S<br>
<input id="l" type="range" min="0" max="255" oninput="changeHS(2,event)">L<br>
<pre class="infoHS"></pre><br>
</div>
Recientemente tuve motivos para resolver este problema y se me ocurrió una solución basada en el lienzo. Lo estoy registrando aquí solo para la posteridad.
En mi caso, también necesitaba tener en cuenta los efectos acumulativos en la conversión, dada una gama de colores de fondo y un canal alfa semitransparente ...
var HSL2COLOR = function () {
return function (hsl, bg) {
function checkHex(v) {
return 1 === v.length ? ''0''+v : v;
}
var data, r, g, b, a,
cnv = document.createElement(''canvas''),
ctx = cnv.getContext(''2d''),
alpha = /a/(/.test(hsl),
output = {};
return cnv.width = cnv.height = 1,
bg && (ctx.fillStyle = bg, ctx.fillRect(0, 0, 1, 1)),
ctx.fillStyle = hsl,
ctx.fillRect(0, 0, 1, 1),
data = ctx.getImageData(0, 0, 1, 1).data,
r = data[0],
g = data[1],
b = data[2],
a = (data[3] / 255).toFixed(2),
alpha ? (output.hsla = hsl, bg ? output.rgb = ''rgb(''+r+'',''+g+'',''+b+'')'' : output.rgba = ''rgb(''+r+'',''+g+'',''+b+'',''+a+'')'') : (output.hsl = hsl, output.rgb = ''rgb(''+r+'',''+g+'',''+b+'')''),
output.hex = ''#''+checkHex(r.toString(16))+checkHex(g.toString(16))+checkHex(b.toString(16)),
output;
};
}();
// hsl: no alpha-channel + no background color
console.log(HSL2COLOR(''hsl(170, 60%, 45%)''));
/*=> {
hsl: "hsl(170, 60%, 45%)",
rgb: "rgb(45,183,160)",
hex: "#2db7a0"
}
*/
// hsla: alpha-channel + no background color
console.log(HSL2COLOR(''hsla(170, 60%, 45%, 0.35)''));
/*=> {
hsla: "hsla(170, 60%, 45%, 0.35)",
rgba: "rgb(42,183,160,0.35)",
hex: "#2ab7a0"
}
*/
// hsla: alpha-channel + background color
console.log(HSL2COLOR(''hsla(170, 60%, 45%, 0.35)'',''#f00''));
/*=> {
hsla: "hsla(170, 60%, 45%, 0.35)",
rgb: "rgb(181,64,56)",
hex: "#b54038"
}
*/
Como puede ver en los resultados anteriores, los valores HEX no son particularmente representativos cuando hay un canal alfa en la entrada pero no se especifica el color de fondo, ya que el lienzo básicamente ve un fondo transparente como negro.
No obstante, el valor
rgba
mantuvo coherente.
De todos modos, logré lo que necesitaba, y tal vez esto sea de alguna utilidad para alguien, en algún momento.
BP
Toma
degree, percentage, percentage
y devuelve el color
hex
CSS:
function hslToHex(h, s, l) {
h /= 360;
s /= 100;
l /= 100;
let r, g, b;
if (s === 0) {
r = g = b = l; // achromatic
} else {
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
};
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
const toHex = x => {
const hex = Math.round(x * 255).toString(16);
return hex.length === 1 ? ''0'' + hex : hex;
};
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}
Ejemplo:
hslToHex(360, 100, 50) // "#ff0000" -> red