Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
548 views
in Technique[技术] by (71.8m points)

colors - Why does the CSS filter hue-rotate produce wierd results?

I'm trying to emulate Photoshop's "Color Overlay" using CSS filters, and while doing so, found out the CSS filters operate on colors as consistently as an epileptic seizure.

Consider the color #FF0000. If we rotate its hue by 120deg, we should get #00FF00, and by 240deg we should get #0000FF. This is the realm of sanity. Now let's enter CSS filters:

body { font: bold 99px Arial }
span { color: #F00; }
.daltonics-wont-notice {
    -webkit-filter: hue-rotate(120deg);
    filter: hue-rotate(120deg);
}
.precision-is-overrated {
    -webkit-filter: hue-rotate(240deg);
    filter: hue-rotate(240deg);
}
<span class="red">?</span>
<span class="daltonics-wont-notice">?</span>
<span class="precision-is-overrated">?</span>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I still cannot believe this is cross-browser. I mean, I've been googling for color spaces and couldn't find any where their definition of "hue" makes sense. They pulled it completely out of their asses, as a big, spiky solid block of galvanized stupidity.

Either way, I have read the inscriptions, and after careful examination of the magic incantations, I've produced a javascript version of the horribly-broken hue-rotate algorithm browsers are currently suffering from.

Here's a jsfiddle version and here's it as a code snippet:

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();
    }
});
body {
    font: 14px sans-serif;
    padding: 6px 8px;
}

input {
    width: 64px;
}
<p>
    This algorithm emulates the wierd, nonsensical and completely 
    idiotic <code>hue-rotate</code> CSS filter. I wanted to know
    how it worked, because it is out of touch with any definition
    of "hue" I've ever seen; the results it produces are stupid
    and I believe it was coded under extreme influence of meth,
    alcohol and caffeine, by a scientologist listening to Death Metal.
</p>
<span>#</span>
<input type="text" id="color" placeholder="RRGGBB">
<input type="text" id="angle" placeholder="degrees">
<button onclick="calculate()">Calculate</button>
<p id="result"></p>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...