hsl 到 rgb 的转换。价值waaaay关闭。与解决方案进行比较。我在做什么不同?
hsl to rgb conversion. Values waaaay off. Compare to solution. What am I doing differently?
已解决!查看编辑
我构建了一个颜色选择器应用程序。很简单的;您单击 rgb 调色板,它会创建一个包含 RGB 值、HSL 值和 HEX 值的样本。
我使用 this formula 进行转换。
基本上,我从具有静态 99% 饱和度的 x 和 y 鼠标位置构建了 HSL 值。
从那里,我通过将 HSL 转换为 RGB 创建了可供选择的调色板。
调色板上的单击事件将创建 RGB、HSL 和 HEX 样本以及每个样本的值。
因为我无法获得匹配的 RGB 和 HSL 值,所以我还没有合并 HEX 值。
我终于找到了可行的解决方案。有人能告诉我我的计算偏离了工作解决方案吗?我不只是想接受可行的解决方案并继续前进;我想知道我的逻辑从哪里开始崩溃。
非常感谢您的帮助!
编辑:所以 Bob__ 建议我使用更好的方法来标准化我的 RGB 值,而不是仅仅根据它们的值加或减 1。我添加了这个函数来根据色调值制作 RGB 通道 (-0.333 - 360.333)
function normalizeRGB(color){
var newVal = (360.333 - (-0.333))/(360.333 - (-0.333)) *
(color- (-0.333) + (-0.333));
return newVal;
}
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Color Picker, Bro</title>
<link href='http://fonts.googleapis.com/css? family=Raleway:700,300' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="style.css">
<script src='https://code.jquery.com/jquery-2.1.3.min.js'></script>
<script type="text/javascript" src='myColorPickerSol.js'></script>
<!-- <script type="text/javascript" src='actualWorkingColorPickerSol.js'></script> -->
</head>
<body>
<div id='container'>
<h1>Color Picker, bro</h1>
<section id='canvas'></section>
<section id='readout'>
<p>HSL: <span id='hsl'></span></p>
<section id='swatchhsl'></section>
<p>RGB: <span id='rgb'></span></p>
<section id='swatchrgb'></section>
<p>HEX: <span id='hex'></span></p>
</section>
</section>
</div>
</body>
</html>
style.css:
body {
background: url(http://subtlepatterns.com/patterns/subtle_white_mini_waves.png);
}
#container {
margin: 0 auto;
width: 800px;
height: inherit;
text-align: center;
font-family: Raleway;
font-weight: 300;
}
#canvas {
margin: 0 auto;
border: 5px solid black;
box-sizing: border-box;
height: 360px;
width: 360px;
}
#readout {
background: rgba(117,117,117, .2);
margin: 20px auto;
height: 400px;
width: 360px;
border: 1px #333 solid;
box-sizing: border-box;
border-radius: 20px;
}
#swatchhsl,#swatchrgb {
margin: 0 auto;
height: 75px;
width: 95%;
border-radius: 20px;
}
p, span {
letter-spacing: 1px;
}
p {
font-weight: 700;
}
span {
font-weight: 300;
}
myColorPickerSol.js
$(document).ready(function(){
var canvas = $('#canvas');
//swatch matches closest when either pure blue, green or red; loses all accuracy when colors mix.
// dark blue gets really close. Purple gets really close, which makes me suspect the Green channel value is where the problem lies.
// y-axis as Luminace(0-100%)
// x-axis as Hue(0-360)
var yPos;
var lum;
var hue;// aka xPos;
var temp1;//for hslToRGB
var temp2;//for hslToRGB
var tempR;
var tempG;
var tempB;
var red;
var blue;
var green;
var realColVal;
$('#canvas').mousemove(function(event){
hue = Math.abs(event.offsetX);
hueForRGB = (hue/360);
yPos = Math.abs(event.offsetY);
lum = (yPos/360);
// console.log(lum + ' lum');
$(canvas).css({'background-color':'hsl('+ event.offsetX + ',99%,'+ Math.round(lum *100) + '%)'});
});
// swatch listener
$(canvas).click(function(event){
hsl2RGB(lum);
$('#rgb').text(red + ','+ green + ',' + blue);
$('#hsl').text(hue + ',99%,' + Math.round(lum * 100) + '%');
$(canvas).css({'background-color':'rgb('+ red + ','+ green + ','+ blue + ')'});
});
//red channel must be in upper third; green in middle third; blue in lower third.
function hsl2RGB(lum){
tempR = (hueForRGB + 0.333);
tempG = hueForRGB;
tempB = (hueForRGB - 0.333);
// set temporary lum based on whether it is above/below 50%
temp1 = lumMorOrLess50(lum);
// set secondary temporary lum value
temp2 = ((2.0 * (lum)) - temp1);
//-----------EDIT -----------------------------
// used the formula to make the tempR|G|B values between 0 and 1
// tempR = makeRGB01(tempR);
// tempG = makeRGB01(tempG);
// tempB = makeRGB01(tempB);
//-----------------------------------------------
red = Math.round(convert2RGB(tempR,temp1,temp2));
green = Math.round(convert2RGB(tempG,temp1,temp2));
blue = Math.round(convert2RGB(tempB,temp1,temp2));
//swatch appears on click for hsl and rgb
$('#swatchhsl').css({'background-color':'hsl('+ hue + ',99%,'+ Math.round(lum * 100 )+ '%)'});
$('#swatchrgb').css({'background-color':'rgb('+ red + ','+ green + ','+ blue + ')'});
};
//force tempR|G|B to be between 0-1
function makeRGB01(input) {
if(input > 1){
input -= 1.0;
} else if(input < 0){
input += 1.0;
};
return input;
};
//get value for each rgb channel
function convert2RGB(tempColVal, val1, val2){
//first convert tempColVal to between 0 and 1 then make it an RGB value
tempColVal = makeRGB01(tempColVal);
//next run 3 test;
if(6.0 * tempColVal < 1){
realColVal = (val2 + (val1 - val2) * 6 * tempColVal);
console.log(realColVal + 'test 1; val1: '+ val1 + 'val2: ' + val2 );
//-------EDIT ------------------------------------------
// test2 will set realColVal to val1 instead of tempColVal
//-------------------------------------------------------
} else if(2.0 * tempColVal < 1){
realColVal = val1;
console.log(realColVal + 'test 2');
} else if(3.0 * tempColVal < 2){
realColVal = (val2 + (val1 - val2)*(0.666 - tempColVal) * 6.0);
console.log(realColVal + 'test 3');
} else {
realColVal = val2;
console.log(realColVal + 'realColVal = default (temp 2)');
};
//-------EDIT ------------------------------------------
// normalize value before multiplying by 255
realColVal = normalizeRGB(realColVal);
//-------------------------------------------------------
// force value between 0 and 1 then set it to RGB scale and
// return
return (Math.abs(realColVal) * 255.0));
};
//configure temporary luminance value, temp1, based on luminance
function lumMorOrLess50(val){
if(val < 0.50){
return ((1.0 + 0.99) * val);
} else {
return ((.99 + val) - (val * .99));
};
};
});
这是可行的解决方案,actualColorPickerSol.js我做了什么不同的事情?
$(function() {
console.log('Loaded, bro');
colorPicker();
});
function colorPicker() {
var canvas = $('#canvas');
canvas.on('mousemove', changeCanvasBackground);
canvas.on('click', printColorReadout);
}
function changeCanvasBackground(event) {
var xCoord = Math.abs(event.offsetX);
var yCoord = Math.abs(event.offsetY);
var rgbValues = 'rgb(' + rgb(hsl(xCoord, yCoord)) + ')';
$(this).css('background', rgbValues);
}
function printColorReadout(event) {
var xCoord = event.offsetX;
var yCoord = event.offsetY;
var hslValues = hsl(xCoord, yCoord);
var rgbValues = rgb(hslValues);
var hexValues = hex(rgbValues);
var hslString = parseHSL(hslValues);
var rgbString = parseRGB(rgbValues);
var hexString = parseHEX(hexValues);
$('#hsl').text(hslString);
$('#rgb').text(rgbString);
$('#hex').text(hexString);
$('#swatchhsl').css('background', hslString);
$('#swatchrgb').css('background', rgbString);
}
function hsl(xCoord, yCoord) {
// HSL = hsl(hue, saturation, luminance)
var hsl;
var hue = xCoord;
var luminance = Math.round(((yCoord / 360) * 100));
return [hue, 100, luminance];
}
function rgb(hslValues) {
var hue = hslValues[0];
var sat = hslValues[1] / 100;
var lum = hslValues[2] / 100;
var tempLum1, tempLum2, tempHue, tempR, tempG, tempB;
if (lum < .50) {
tempLum1 = lum * (1 + sat);
} else {
tempLum1 = (lum + sat) - (lum * sat);
}
tempLum2 = (2 * lum) - tempLum1;
tempHue = hue / 360;
tempR = tempHue + .333;
tempG = tempHue;
tempB = tempHue - .333;
//This is the only part I think I did differently.
//The code below makes sure the green and blue values
//are between 0 and 1, then it checks all the colors to
//make sure they are between 0 and 1. I tried this,
// and there was no change in the effect;
// the hsl and rgb values were still different.
if (tempG < 0) { tempG += 1};
if (tempG > 1) { tempG -= 1};
if (tempB < 0) { tempB += 1};
if (tempB > 1) { tempB -= 1};
var normalizedRGB = [tempR, tempG, tempB].map(function(color, idx) {
if (color < 0) { return color += 1};
if (color > 1) { return color -= 1};
return color;
});
var rgbArray = normalizedRGB.map(function(color) {
if (colorCondition1(color)) {
return tempLum2 + ( tempLum1 - tempLum2 ) * 6 * color;
} else if (colorCondition2(color)) {
return tempLum1;
} else if (colorCondition3(color)) {
return tempLum2 + (tempLum1 - tempLum2) * (.666 - color) * 6;
} else {
return tempLum2;
}
});
var rgbValues = rgbArray.map(function(color, idx) {
var convertedVal = color * 255;
return Math.round(convertedVal);
});
return rgbValues;
}
function hex(rgbValues) {
var r = rgbValues[0];
var g = rgbValues[1];
var b = rgbValues[2];
return [numToHex(r), numToHex(g), numToHex(b)];
}
function numToHex(num) {
var hexCode = num.toString(16);
if (hexCode.length < 2) { hexCode = "0" + hexCode; }
return hexCode;
}
function colorCondition1(val) {
return 6 * val < 1;
}
function colorCondition2(val) {
return 2 * val < 1;
}
function colorCondition3(val) {
return 3 * val < 2;
}
function parseHSL(hslValues) {
return [
"hsl(",
hslValues[0], ", ",
hslValues[1], "%, ",
hslValues[2], "%)"
].join('');
}
function parseRGB(rgbValues) {
return "rgb(" + rgbValues.join(', ') + ")";
}
function parseHEX(hexValues) {
return "#" + hexValues.join('');
}
将您的函数与您发布的 link 中提供的算法进行比较,我认为更正确的 convert2RGB 实现,正如我在评论中所说,可能是:
function convert2RGB(tempColVal, val1, val2){
//first convert tempColVal to between 0 and 1 then make it an RGB value
tempColVal = makeRGB01(tempColVal);
//next run 3 test;
if(6.0 * tempColVal < 1){
realColVal = (val2 + (val1 - val2) * 6.0 * tempColVal);
// console.log(realColVal + 'test 1; val1: '+ val1 + 'val2: ' + val2 );
} else if(2.0 * tempColVal < 1){
realColVal = val1;
// console.log(realColVal + 'test 2');
} else if(3.0 * tempColVal < 2){
realColVal = (val2 + (val1 - val2)*(0.666 - tempColVal) * 6.0);
// console.log(realColVal + 'test 3');
} else {
realColVal = val2;
// console.log(realColVal + 'realColVal = default (temp 2)');
};
// Convert them to 8-bit by multiply them with 255 and return
return Math.round(realColVal * 255.0);
};
编辑:
不要更改您的 makeRGB01()
,因为该算法的使用方式与调用 convert2RGB()
之前相同。您的错误是将其也应用于返回的更正值。
已解决!查看编辑
我构建了一个颜色选择器应用程序。很简单的;您单击 rgb 调色板,它会创建一个包含 RGB 值、HSL 值和 HEX 值的样本。
我使用 this formula 进行转换。
基本上,我从具有静态 99% 饱和度的 x 和 y 鼠标位置构建了 HSL 值。
从那里,我通过将 HSL 转换为 RGB 创建了可供选择的调色板。
调色板上的单击事件将创建 RGB、HSL 和 HEX 样本以及每个样本的值。
因为我无法获得匹配的 RGB 和 HSL 值,所以我还没有合并 HEX 值。
我终于找到了可行的解决方案。有人能告诉我我的计算偏离了工作解决方案吗?我不只是想接受可行的解决方案并继续前进;我想知道我的逻辑从哪里开始崩溃。
非常感谢您的帮助!
编辑:所以 Bob__ 建议我使用更好的方法来标准化我的 RGB 值,而不是仅仅根据它们的值加或减 1。我添加了这个函数来根据色调值制作 RGB 通道 (-0.333 - 360.333)
function normalizeRGB(color){
var newVal = (360.333 - (-0.333))/(360.333 - (-0.333)) *
(color- (-0.333) + (-0.333));
return newVal;
}
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Color Picker, Bro</title>
<link href='http://fonts.googleapis.com/css? family=Raleway:700,300' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="style.css">
<script src='https://code.jquery.com/jquery-2.1.3.min.js'></script>
<script type="text/javascript" src='myColorPickerSol.js'></script>
<!-- <script type="text/javascript" src='actualWorkingColorPickerSol.js'></script> -->
</head>
<body>
<div id='container'>
<h1>Color Picker, bro</h1>
<section id='canvas'></section>
<section id='readout'>
<p>HSL: <span id='hsl'></span></p>
<section id='swatchhsl'></section>
<p>RGB: <span id='rgb'></span></p>
<section id='swatchrgb'></section>
<p>HEX: <span id='hex'></span></p>
</section>
</section>
</div>
</body>
</html>
style.css:
body {
background: url(http://subtlepatterns.com/patterns/subtle_white_mini_waves.png);
}
#container {
margin: 0 auto;
width: 800px;
height: inherit;
text-align: center;
font-family: Raleway;
font-weight: 300;
}
#canvas {
margin: 0 auto;
border: 5px solid black;
box-sizing: border-box;
height: 360px;
width: 360px;
}
#readout {
background: rgba(117,117,117, .2);
margin: 20px auto;
height: 400px;
width: 360px;
border: 1px #333 solid;
box-sizing: border-box;
border-radius: 20px;
}
#swatchhsl,#swatchrgb {
margin: 0 auto;
height: 75px;
width: 95%;
border-radius: 20px;
}
p, span {
letter-spacing: 1px;
}
p {
font-weight: 700;
}
span {
font-weight: 300;
}
myColorPickerSol.js
$(document).ready(function(){
var canvas = $('#canvas');
//swatch matches closest when either pure blue, green or red; loses all accuracy when colors mix.
// dark blue gets really close. Purple gets really close, which makes me suspect the Green channel value is where the problem lies.
// y-axis as Luminace(0-100%)
// x-axis as Hue(0-360)
var yPos;
var lum;
var hue;// aka xPos;
var temp1;//for hslToRGB
var temp2;//for hslToRGB
var tempR;
var tempG;
var tempB;
var red;
var blue;
var green;
var realColVal;
$('#canvas').mousemove(function(event){
hue = Math.abs(event.offsetX);
hueForRGB = (hue/360);
yPos = Math.abs(event.offsetY);
lum = (yPos/360);
// console.log(lum + ' lum');
$(canvas).css({'background-color':'hsl('+ event.offsetX + ',99%,'+ Math.round(lum *100) + '%)'});
});
// swatch listener
$(canvas).click(function(event){
hsl2RGB(lum);
$('#rgb').text(red + ','+ green + ',' + blue);
$('#hsl').text(hue + ',99%,' + Math.round(lum * 100) + '%');
$(canvas).css({'background-color':'rgb('+ red + ','+ green + ','+ blue + ')'});
});
//red channel must be in upper third; green in middle third; blue in lower third.
function hsl2RGB(lum){
tempR = (hueForRGB + 0.333);
tempG = hueForRGB;
tempB = (hueForRGB - 0.333);
// set temporary lum based on whether it is above/below 50%
temp1 = lumMorOrLess50(lum);
// set secondary temporary lum value
temp2 = ((2.0 * (lum)) - temp1);
//-----------EDIT -----------------------------
// used the formula to make the tempR|G|B values between 0 and 1
// tempR = makeRGB01(tempR);
// tempG = makeRGB01(tempG);
// tempB = makeRGB01(tempB);
//-----------------------------------------------
red = Math.round(convert2RGB(tempR,temp1,temp2));
green = Math.round(convert2RGB(tempG,temp1,temp2));
blue = Math.round(convert2RGB(tempB,temp1,temp2));
//swatch appears on click for hsl and rgb
$('#swatchhsl').css({'background-color':'hsl('+ hue + ',99%,'+ Math.round(lum * 100 )+ '%)'});
$('#swatchrgb').css({'background-color':'rgb('+ red + ','+ green + ','+ blue + ')'});
};
//force tempR|G|B to be between 0-1
function makeRGB01(input) {
if(input > 1){
input -= 1.0;
} else if(input < 0){
input += 1.0;
};
return input;
};
//get value for each rgb channel
function convert2RGB(tempColVal, val1, val2){
//first convert tempColVal to between 0 and 1 then make it an RGB value
tempColVal = makeRGB01(tempColVal);
//next run 3 test;
if(6.0 * tempColVal < 1){
realColVal = (val2 + (val1 - val2) * 6 * tempColVal);
console.log(realColVal + 'test 1; val1: '+ val1 + 'val2: ' + val2 );
//-------EDIT ------------------------------------------
// test2 will set realColVal to val1 instead of tempColVal
//-------------------------------------------------------
} else if(2.0 * tempColVal < 1){
realColVal = val1;
console.log(realColVal + 'test 2');
} else if(3.0 * tempColVal < 2){
realColVal = (val2 + (val1 - val2)*(0.666 - tempColVal) * 6.0);
console.log(realColVal + 'test 3');
} else {
realColVal = val2;
console.log(realColVal + 'realColVal = default (temp 2)');
};
//-------EDIT ------------------------------------------
// normalize value before multiplying by 255
realColVal = normalizeRGB(realColVal);
//-------------------------------------------------------
// force value between 0 and 1 then set it to RGB scale and
// return
return (Math.abs(realColVal) * 255.0));
};
//configure temporary luminance value, temp1, based on luminance
function lumMorOrLess50(val){
if(val < 0.50){
return ((1.0 + 0.99) * val);
} else {
return ((.99 + val) - (val * .99));
};
};
});
这是可行的解决方案,actualColorPickerSol.js我做了什么不同的事情?
$(function() {
console.log('Loaded, bro');
colorPicker();
});
function colorPicker() {
var canvas = $('#canvas');
canvas.on('mousemove', changeCanvasBackground);
canvas.on('click', printColorReadout);
}
function changeCanvasBackground(event) {
var xCoord = Math.abs(event.offsetX);
var yCoord = Math.abs(event.offsetY);
var rgbValues = 'rgb(' + rgb(hsl(xCoord, yCoord)) + ')';
$(this).css('background', rgbValues);
}
function printColorReadout(event) {
var xCoord = event.offsetX;
var yCoord = event.offsetY;
var hslValues = hsl(xCoord, yCoord);
var rgbValues = rgb(hslValues);
var hexValues = hex(rgbValues);
var hslString = parseHSL(hslValues);
var rgbString = parseRGB(rgbValues);
var hexString = parseHEX(hexValues);
$('#hsl').text(hslString);
$('#rgb').text(rgbString);
$('#hex').text(hexString);
$('#swatchhsl').css('background', hslString);
$('#swatchrgb').css('background', rgbString);
}
function hsl(xCoord, yCoord) {
// HSL = hsl(hue, saturation, luminance)
var hsl;
var hue = xCoord;
var luminance = Math.round(((yCoord / 360) * 100));
return [hue, 100, luminance];
}
function rgb(hslValues) {
var hue = hslValues[0];
var sat = hslValues[1] / 100;
var lum = hslValues[2] / 100;
var tempLum1, tempLum2, tempHue, tempR, tempG, tempB;
if (lum < .50) {
tempLum1 = lum * (1 + sat);
} else {
tempLum1 = (lum + sat) - (lum * sat);
}
tempLum2 = (2 * lum) - tempLum1;
tempHue = hue / 360;
tempR = tempHue + .333;
tempG = tempHue;
tempB = tempHue - .333;
//This is the only part I think I did differently.
//The code below makes sure the green and blue values
//are between 0 and 1, then it checks all the colors to
//make sure they are between 0 and 1. I tried this,
// and there was no change in the effect;
// the hsl and rgb values were still different.
if (tempG < 0) { tempG += 1};
if (tempG > 1) { tempG -= 1};
if (tempB < 0) { tempB += 1};
if (tempB > 1) { tempB -= 1};
var normalizedRGB = [tempR, tempG, tempB].map(function(color, idx) {
if (color < 0) { return color += 1};
if (color > 1) { return color -= 1};
return color;
});
var rgbArray = normalizedRGB.map(function(color) {
if (colorCondition1(color)) {
return tempLum2 + ( tempLum1 - tempLum2 ) * 6 * color;
} else if (colorCondition2(color)) {
return tempLum1;
} else if (colorCondition3(color)) {
return tempLum2 + (tempLum1 - tempLum2) * (.666 - color) * 6;
} else {
return tempLum2;
}
});
var rgbValues = rgbArray.map(function(color, idx) {
var convertedVal = color * 255;
return Math.round(convertedVal);
});
return rgbValues;
}
function hex(rgbValues) {
var r = rgbValues[0];
var g = rgbValues[1];
var b = rgbValues[2];
return [numToHex(r), numToHex(g), numToHex(b)];
}
function numToHex(num) {
var hexCode = num.toString(16);
if (hexCode.length < 2) { hexCode = "0" + hexCode; }
return hexCode;
}
function colorCondition1(val) {
return 6 * val < 1;
}
function colorCondition2(val) {
return 2 * val < 1;
}
function colorCondition3(val) {
return 3 * val < 2;
}
function parseHSL(hslValues) {
return [
"hsl(",
hslValues[0], ", ",
hslValues[1], "%, ",
hslValues[2], "%)"
].join('');
}
function parseRGB(rgbValues) {
return "rgb(" + rgbValues.join(', ') + ")";
}
function parseHEX(hexValues) {
return "#" + hexValues.join('');
}
将您的函数与您发布的 link 中提供的算法进行比较,我认为更正确的 convert2RGB 实现,正如我在评论中所说,可能是:
function convert2RGB(tempColVal, val1, val2){
//first convert tempColVal to between 0 and 1 then make it an RGB value
tempColVal = makeRGB01(tempColVal);
//next run 3 test;
if(6.0 * tempColVal < 1){
realColVal = (val2 + (val1 - val2) * 6.0 * tempColVal);
// console.log(realColVal + 'test 1; val1: '+ val1 + 'val2: ' + val2 );
} else if(2.0 * tempColVal < 1){
realColVal = val1;
// console.log(realColVal + 'test 2');
} else if(3.0 * tempColVal < 2){
realColVal = (val2 + (val1 - val2)*(0.666 - tempColVal) * 6.0);
// console.log(realColVal + 'test 3');
} else {
realColVal = val2;
// console.log(realColVal + 'realColVal = default (temp 2)');
};
// Convert them to 8-bit by multiply them with 255 and return
return Math.round(realColVal * 255.0);
};
编辑:
不要更改您的 makeRGB01()
,因为该算法的使用方式与调用 convert2RGB()
之前相同。您的错误是将其也应用于返回的更正值。