通过阅读HSL / HSV色彩理论,我得到的印象是色调分量是一个循环属性,每360度重复一次,并且可以独立于饱和度和亮度/值进行更改。如果我错了,请纠正我,但这些陈述逻辑上遵循先前的定义:
但是,只有选项1是正确的。将色调旋转4次+90度会产生与原始颜色甚至不相似的颜色。
此外,使用-webkit-filter和SVG的
<filter><feColorMatrix in="SourceGraphic" type="hueRotate" values="..." /></filter>
对于相同的旋转不会产生相同的结果。另一方面,SVG过滤器产生的颜色在浏览器中是一致的。
是否存在色调旋转的“隐藏”属性,使操作不相关?
可以在此处找到webkit过滤器和SVG的示例:http://jsfiddle.net/maros_urbanec/ARsjb/5/
答案 0 :(得分:32)
在CSS和SVG滤镜中,没有转换为HSV或HSL - hueRotation短边使用RGB空间中的线性矩阵近似来执行色调旋转。对于小旋转和高度饱和的颜色,这不能很好地保持饱和度或亮度 - 正如您所看到的那样。
真正的色调旋转,首先将输入RGB颜色转换为HSL,调整H然后转换回RGB。过滤器不会这样做。并且这种转换不能用线性矩阵精确地近似,因此当色调被准确地改变(大多数)时,饱和度和亮度遍布整个地方。这些效果是非线性的,因此将较小的ops加在一起会产生不同的颜色,而不是进行一次大的操作。
(SVG和CSS过滤器中的huerotation之间的差异可能是由于使用了不同的颜色空间(sRGB与linearRGB) - 这些应相同。)
更新:我有兴趣去做一个手动比较。正如您所看到的,过滤器在0到180度范围内旋转纯色的色调非常糟糕。此图像比较通过手动插入hsl颜色(外环)与基色(内环)上的滤镜色调旋转完成的手动色调旋转
但是,正如你所看到的,他们在hsl(0,50%,75%)这些不太纯净的颜色方面做得更好。
如果您想玩,请使用codepen链接:http://codepen.io/mullany/pen/fwHrd
答案 1 :(得分:5)
hue-rotate
。
同样,这里的重点只是了解它产生的结果。
hue-rotate
&#13;
function calculate() {
// Get the RGB and angle to work with.
var color = document.getElementById('color').value;
if (! /^[0-9A-F]{6}$/i.test(color)) return alert('Bad color!');
var angle = document.getElementById('angle').value;
if (! /^-?[0-9]+$/i.test(angle)) return alert('Bad angle!');
var r = parseInt(color.substr(0, 2), 16);
var g = parseInt(color.substr(2, 2), 16);
var b = parseInt(color.substr(4, 2), 16);
var angle = (parseInt(angle) % 360 + 360) % 360;
// Hold your breath because what follows isn't flowers.
var matrix = [ // Just remember this is the identity matrix for
1, 0, 0, // Reds
0, 1, 0, // Greens
0, 0, 1 // Blues
];
// Luminance coefficients.
var lumR = 0.2126;
var lumG = 0.7152;
var lumB = 0.0722;
// Hue rotate coefficients.
var hueRotateR = 0.143;
var hueRotateG = 0.140;
var hueRotateB = 0.283;
var cos = Math.cos(angle * Math.PI / 180);
var sin = Math.sin(angle * Math.PI / 180);
matrix[0] = lumR + (1 - lumR) * cos - lumR * sin;
matrix[1] = lumG - lumG * cos - lumG * sin;
matrix[2] = lumB - lumB * cos + (1 - lumB) * sin;
matrix[3] = lumR - lumR * cos + hueRotateR * sin;
matrix[4] = lumG + (1 - lumG) * cos + hueRotateG * sin;
matrix[5] = lumB - lumB * cos - hueRotateB * sin;
matrix[6] = lumR - lumR * cos - (1 - lumR) * sin;
matrix[7] = lumG - lumG * cos + lumG * sin;
matrix[8] = lumB + (1 - lumB) * cos + lumB * sin;
function clamp(num) {
return Math.round(Math.max(0, Math.min(255, num)));
}
var R = clamp(matrix[0] * r + matrix[1] * g + matrix[2] * b);
var G = clamp(matrix[3] * r + matrix[4] * g + matrix[5] * b);
var B = clamp(matrix[6] * r + matrix[7] * g + matrix[8] * b);
// Output the result
var result = 'The original color, rgb(' + [r,g,b] + '), '
+ 'when rotated by ' + angle + ' degrees '
+ 'by the devil\'s logic, gives you '
+ 'rgb(' + [R,G,B] + '). If I got it right.';
document.getElementById('result').innerText = result;
}
// Listen for Enter key press.
['color', 'angle'].forEach(function(i) {
document.getElementById(i).onkeypress = function(event) {
var e = event || window.event, c = e.which || e.keyCode;
if (c == '13') return calculate();
}
});
&#13;
body {
font: 14px sans-serif;
padding: 6px 8px;
}
input {
width: 64px;
}
&#13;
摘录摘自this answer。
答案 2 :(得分:1)
tl; dr 将颜色从浮点数(在过滤器内)转换为字节(其他地方)时出错。
因此它有点复杂,spec为色调旋转矩阵提供了一个很好的公式,例如180度的公式(不包括alpha和shift):
-0.5747 1.4304 0.1444
0.4252 0.4304 0.1444
0.4252 1.4304 -0.8556
注意,如果你自己乘以它(到小数点后四位):
0.9999 0.0001 0.0000
0.0000 1.0 0.0
0.0000 0.0000 1.0
非常接近单位矩阵或空转换。
除了浏览器在每个过滤器之间转换回RGB之外,这将是完美的。看看当我们旋转亮红色时会发生什么:
-0.5747 1.4304 0.1444 1 -0.5747
0.4252 0.4304 0.1444 * 0 = 0.4252
0.4252 1.4304 -0.8556 0 0.4252
我们得到的颜色在RGB中无法用0到255的值表示。因此它在RGB转换过程中被绑定并四舍五入为0 0.4235 0.4235
,并且当它再次旋转时我们最终得到了一种黑色的去饱和红色,0.6667 0.2431 0.2431
而不是我们开始时的明亮的纯红色。