我想知道增加或减少一个RGB颜色饱和度的算法
例如,如果我有颜色rgb(200, 30, 40)
(红色),则函数存根将是
function Saturation(color, factor)
where color.r = 200, color.g= 30 and color.b=40
任何人都知道图书馆或有代码片段吗?
答案 0 :(得分:10)
按照巴厘岛巴洛的建议,我提出了:
RGBtoHSV= function(color) {
var r,g,b,h,s,v;
r= color[0];
g= color[1];
b= color[2];
min = Math.min( r, g, b );
max = Math.max( r, g, b );
v = max;
delta = max - min;
if( max != 0 )
s = delta / max; // s
else {
// r = g = b = 0 // s = 0, v is undefined
s = 0;
h = -1;
return [h, s, undefined];
}
if( r === max )
h = ( g - b ) / delta; // between yellow & magenta
else if( g === max )
h = 2 + ( b - r ) / delta; // between cyan & yellow
else
h = 4 + ( r - g ) / delta; // between magenta & cyan
h *= 60; // degrees
if( h < 0 )
h += 360;
if ( isNaN(h) )
h = 0;
return [h,s,v];
};
HSVtoRGB= function(color) {
var i;
var h,s,v,r,g,b;
h= color[0];
s= color[1];
v= color[2];
if(s === 0 ) {
// achromatic (grey)
r = g = b = v;
return [r,g,b];
}
h /= 60; // sector 0 to 5
i = Math.floor( h );
f = h - i; // factorial part of h
p = v * ( 1 - s );
q = v * ( 1 - s * f );
t = v * ( 1 - s * ( 1 - f ) );
switch( i ) {
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
default: // case 5:
r = v;
g = p;
b = q;
break;
}
return [r,g,b];
}
通过转换为HSV(色调,饱和度和值)格式,您可以这种方式手动更改S组件:
var hsv= RGBtoHSV ([200,100,100]);
alert(hsv)
hsv[1] *= 1.5;
alert(hsv)
var rgb= HSVtoRGB(hsv);
alert(rgb); //new color
答案 1 :(得分:6)
这是一种快速而肮脏的方式,可能在任何技术方面都不正确,但涉及的计算量少于转换为HSV和返回(如果重要的话,渲染速度更快):
灰度等效于计算像素的RGB部分的平均亮度。我们可以通过对灰色部分和彩色部分应用值加权来混合灰度:
var pixels = context.getImageData(0, 0, canvas.width, canvas.height);
grayscale = function (pixels, value) {
var d = pixels.data;
for (var i = 0; i < d.length; i += 4) {
var r = d[i];
var g = d[i + 1];
var b = d[i + 2];
var gray = 0.2989*r + 0.5870*g + 0.1140*b; //weights from CCIR 601 spec
d[i] = gray * value + d[i] * (1-value);
d[i+1] = gray * value + d[i+1] * (1-value);
d[i+2] = gray * value + d[i+2] * (1-value);
}
return pixels;
};
因此,我们不会添加“灰度”,而是将其取出并将相关颜色添加回“饱和”:
saturate = function (pixels, value) {
var d = pixels.data;
for (var i = 0; i < d.length; i += 4) {
var r = d[i];
var g = d[i + 1];
var b = d[i + 2];
var gray = 0.2989*r + 0.5870*g + 0.1140*b; //weights from CCIR 601 spec
d[i] = -gray * value + d[i] * (1+value);
d[i+1] = -gray * value + d[i+1] * (1+value);
d[i+2] = -gray * value + d[i+2] * (1+value);
//normalize over- and under-saturated values
if(d[i] > 255) d[i] = 255;
if(d[i+1] > 255) d[i] = 255;
if(d[i+2] > 255) d[i] = 255;
if(d[i] < 0) d[i] = 0;
if(d[i+1] < 0) d[i] = 0;
if(d[i+2] < 0) d[i] = 0;
}
return pixels;
};
同样,免责声明这种“看起来”已经饱和但可能绝不会遵循“饱和度”的技术定义(无论是什么);我只是发布了这个,希望它对路人有帮助。
答案 2 :(得分:3)
//我的解决方案适用于HEX格式的颜色。您可以按百分比请求饱和度。
function applySaturationToHexColor(hex, saturationPercent) {
if (!/^#([0-9a-f]{6})$/i.test(hex)) {
throw('Unexpected color format');
}
if (saturationPercent < 0 || saturationPercent > 100) {
throw('Unexpected color format');
}
var saturationFloat = saturationPercent / 100,
rgbIntensityFloat = [
parseInt(hex.substr(1,2), 16) / 255,
parseInt(hex.substr(3,2), 16) / 255,
parseInt(hex.substr(5,2), 16) / 255
];
var rgbIntensityFloatSorted = rgbIntensityFloat.slice(0).sort(function(a, b){ return a - b; }),
maxIntensityFloat = rgbIntensityFloatSorted[2],
mediumIntensityFloat = rgbIntensityFloatSorted[1],
minIntensityFloat = rgbIntensityFloatSorted[0];
if (maxIntensityFloat == minIntensityFloat) {
// All colors have same intensity, which means
// the original color is gray, so we can't change saturation.
return hex;
}
// New color max intensity wont change. Lets find medium and weak intensities.
var newMediumIntensityFloat,
newMinIntensityFloat = maxIntensityFloat * (1 - saturationFloat);
if (mediumIntensityFloat == minIntensityFloat) {
// Weak colors have equal intensity.
newMediumIntensityFloat = newMinIntensityFloat;
}
else {
// Calculate medium intensity with respect to original intensity proportion.
var intensityProportion = (maxIntensityFloat - mediumIntensityFloat) / (mediumIntensityFloat - minIntensityFloat);
newMediumIntensityFloat = (intensityProportion * newMinIntensityFloat + maxIntensityFloat) / (intensityProportion + 1);
}
var newRgbIntensityFloat = [],
newRgbIntensityFloatSorted = [newMinIntensityFloat, newMediumIntensityFloat, maxIntensityFloat];
// We've found new intensities, but we have then sorted from min to max.
// Now we have to restore original order.
rgbIntensityFloat.forEach(function(originalRgb) {
var rgbSortedIndex = rgbIntensityFloatSorted.indexOf(originalRgb);
newRgbIntensityFloat.push(newRgbIntensityFloatSorted[rgbSortedIndex]);
});
var floatToHex = function(val) { return ('0' + Math.round(val * 255).toString(16)).substr(-2); },
rgb2hex = function(rgb) { return '#' + floatToHex(rgb[0]) + floatToHex(rgb[1]) + floatToHex(rgb[2]); };
var newHex = rgb2hex(newRgbIntensityFloat);
return newHex;
}