Javascript 在javascript中“自然地”混合两种颜色
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14819058/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Mixing two colors "naturally" in javascript
提问by Tamás Pap
The problem:I want to mix two colors in javascript, and get the result color. There are a lot of similar question on SO, however I doesn't find anything that actually works correctly. I know that mixing two different colored paints(pigments) and lights will give very different results (http://en.wikipedia.org/wiki/Color_mixing).
问题:我想在javascript中混合两种颜色,并获得结果颜色。SO上有很多类似的问题,但是我没有发现任何实际工作正常的问题。我知道混合两种不同颜色的颜料(颜料)和灯光会产生非常不同的结果(http://en.wikipedia.org/wiki/Color_mixing)。
Here are the questions and suggested solutions I've already seen, and tried to implement:
以下是我已经看到并尝试实施的问题和建议的解决方案:
1:Mixing two RGB color vectors to get resultant
So, mixing colors in RGB. I implemented it, and in some cases it works in some cases it doesn't.
1:混合两个RGB颜色向量得到结果
所以,在RGB中混合颜色。我实现了它,在某些情况下它起作用,在某些情况下它不起作用。
Working example:Mixing redwith yellow-> orange. Great!
http://jsbin.com/afomim/1/edit
工作示例:red与yellow->混合orange。伟大的!
http://jsbin.com/afoim/1/edit
Not working example:Mixing bluewith yellow-> gray. Not so great! :)
http://jsbin.com/afomim/5/edit
I know that in RGB mixing bluewith yellowwill never make green, and I understand why.
不工作的例子:blue与yellow->混合gray。不太好!:)
http://jsbin.com/afomim/5/edit
我知道,在RGB混合blue使用yellow不会让green的,我明白为什么。
We will not find the answer here, let's go forward.
我们不会在这里找到答案,让我们继续前进。
2:Adding Colours (Colors) Together like Paint (Blue + Yellow = Green, etc)
Let's try to work with CMYK values as suggested in this discussion. Mixing cyanwith yellowgives green:
http://jsbin.com/igaveg/1/edit
but mixing bluewith yellowresults in black.
http://jsbin.com/igaveg/2/edit-> Not working!
让我们尝试使用本讨论中建议的 CMYK 值。混合cyan与yellow给出green:
http://jsbin.com/igaveg/1/edit
但混合blue使用yellow的结果black。
http://jsbin.com/igaveg/2/edit-> 不工作!
3:How to mix colors "naturally" with C#?
A very similar question. The most upvoted answer suggests to convert colors to LAB, and this solution seems promising.
So I converted my colors to LAB. The conversion algo is correct, I tested it!
3:如何用C#“自然地”混合颜色?
一个非常相似的问题。最受好评的答案建议将颜色转换为 LAB,这个解决方案似乎很有希望。
所以我将我的颜色转换为 LAB。转换算法是正确的,我测试过了!
http://jsbin.com/oxefox/1/edit
http://jsbin.com/oxefox/1/edit
Now I have the two colors in LAB, but how to mix them?
现在我在 LAB 中有两种颜色,但是如何混合它们呢?
NOTEI know that probably I will not find an algo that mixes bluewith yellowand will give the perfect green, but I hope I can generate something similar to green :)
注:我知道,可能我不会找到一个算法中混合了blue有yellow和将会给完美的green,但我希望我能够生成类似于绿色的东西:)
回答by Tamás Pap
I dedicated 3-4 days to this question. It's a really complex problem.
我花了 3-4 天的时间来回答这个问题。这是一个非常复杂的问题。
Here is what you can do if you want to mix two colors "naturally":
如果您想“自然地”混合两种颜色,您可以这样做:
CMYK mixing: it's not the perfect solution, but if you need a solution now, and you don't want to spend months with learning about the subject, experimenting and coding, you can check this out: https://github.com/AndreasStheitroadon/Color_mixer
Implementing the Kubelka-Munk theory. I spent a lot of time reading about it, and trying to understand it. This should be the way to go if you want a professional solution, but it needs 6 parameters (like reflectance, absorption, etc.) for each colors you want to mix. Having R, G, B isn't enough. Implementing the theory isn't hard, but getting those parameters you need about each color seems to be the missing part. If you figure it out how to do it, let me know :)
Experimental: you can do something what the developers of the ipad app: Paperhave done. They manually selected 100 pairs of popular colors and eyeball-tested how they should blend. Learn more about it here.
CMYK 混合:这不是完美的解决方案,但如果您现在需要一个解决方案,并且您不想花费数月时间学习该主题、实验和编码,您可以查看:https: //github.com/ AndreasStheitroadon/Color_mixer
实施 Kubelka-Munk 理论。我花了很多时间阅读它,并试图理解它。如果您想要专业的解决方案,这应该是可行的方法,但对于您想要混合的每种颜色,它需要 6 个参数(如反射率、吸收率等)。有 R、G、B 是不够的。实施该理论并不难,但获取有关每种颜色所需的参数似乎是缺失的部分。如果你知道怎么做,请告诉我:)
实验性:您可以做一些 ipad 应用程序的开发人员:Paper所做的事情。他们手动选择了 100 对流行的颜色,并用眼球测试了它们应该如何混合。在此处了解更多信息。
I personally will implement the CMYK mixing for the moment, and maybe later, if I have time I'll try to make something like the guys at Fiftythree. Will see :)
我个人将暂时实施 CMYK 混合,也许以后,如果我有时间,我会尝试制作像 Fiftythree 那样的东西。等着瞧 :)
回答by Martin R
The RYB Color Modelcould be a suitable choice for the color mixing calculations. According to Wikipedia, it is primarily used in art and design education, particularly painting.
该RYB颜色模型可能是混色计算一个合适的选择。根据维基百科,它主要用于艺术和设计教育,尤其是绘画。
To mix 2 colors, one converts both colors from RGB to RYB, mixes the colors by adding each color component, and converts the resulting color from RYB back to RGB.
要混合 2 种颜色,将两种颜色从 RGB 转换为 RYB,通过添加每个颜色分量来混合颜色,然后将生成的颜色从 RYB 转换回 RGB。
I have tried this using the Online Color Mixing Tool, and the results are
我已经使用Online Color Mixing Tool尝试过这个,结果是
0000FF (blue) mixed with #FFFF00 (yellow) gives #008000 (dark green),
FF0000 (red) mixed with #FFFF00 (yellow) gives #FFA000 (orange).
0000FF(蓝色)与#FFFF00(黄色)混合得到#008000(深绿色),
FF0000(红色)与#FFFF00(黄色)混合得到#FFA000(橙色)。
So this method produces exactly the results that you expected.
所以这个方法产生的结果正是你所期望的。
Unfortunately, I was not able to find a reference with "ready-to-use" formula to convert from RGB to RYB and back to RGB.
不幸的是,我无法找到带有“即用型”公式的参考,以将 RGB 转换为 RYB,然后再转换回 RGB。
The paper Paint Inspired Color Mixing and Compositing for Visualisation - Gossett and Chendescribes the general idea of the RYB color model in the section "2 ACHIEVING INTUITIVE COLOR MIXING".
论文 Paint Inspired Color Mixing and Compositing for Visualization - Gossett and Chen在“2 ACHIEVING INTUITIVE COLOR MIXING”一节中描述了 RYB 颜色模型的一般思想。
According to that paper, the conversion from RYB to RGB is done by Trilinear interpolation.
根据那篇论文,从 RYB 到 RGB 的转换是通过三线性插值完成的 。
The difficult part is the conversion from RGB to RYB, because it requires the inversion of the trilinear interpolation. See Conversion between RGB and RYB color spacesfor more more information.
难点是RGB到RYB的转换,因为它需要三线性插值的反演。有关 更多信息,请参阅RGB 和 RYB 颜色空间之间的转换。
Even if this answer does not provide complete formula for the calculation, I hope that it gives some ideas how to proceed.
即使这个答案没有提供完整的计算公式,我希望它给出一些如何进行的想法。
回答by Aaron Harris
I actually ran into the same issue when trying to mix 2 RGB colors together. These 2 functions worked for me:
在尝试将 2 种 RGB 颜色混合在一起时,我实际上遇到了同样的问题。这两个功能对我有用:
//colorChannelA and colorChannelB are ints ranging from 0 to 255
function colorChannelMixer(colorChannelA, colorChannelB, amountToMix){
var channelA = colorChannelA*amountToMix;
var channelB = colorChannelB*(1-amountToMix);
return parseInt(channelA+channelB);
}
//rgbA and rgbB are arrays, amountToMix ranges from 0.0 to 1.0
//example (red): rgbA = [255,0,0]
function colorMixer(rgbA, rgbB, amountToMix){
var r = colorChannelMixer(rgbA[0],rgbB[0],amountToMix);
var g = colorChannelMixer(rgbA[1],rgbB[1],amountToMix);
var b = colorChannelMixer(rgbA[2],rgbB[2],amountToMix);
return "rgb("+r+","+g+","+b+")";
}
To mix red ( [255,0,0] ) with blue ( [0,0,255] ) evenly, you can call
要将红色 ( [255,0,0] ) 与蓝色 ( [0,0,255] ) 均匀混合,您可以调用
colorMixer([255,0,0], [0,0,255], 0.5);//returns "rgb(127,0,127)" (purple)
This may help, though you have to convert each color value to an array first. If you use Fabric.js to work with canvas elements, this becomes really easy. Just call
这可能会有所帮助,但您必须先将每个颜色值转换为数组。如果您使用 Fabric.js 来处理画布元素,这将变得非常简单。打电话就行
var rgbA = new fabric.Color(yourColor);
var rgbB = new fabric.Color(yourSecondColor);
then call
然后打电话
colorMixer(rgbA.getSource(),rgbB.getSource(),0.5);
Hope these functions help.
希望这些功能有所帮助。
回答by Plynx
With CIELAB colors you have three coordinates for each of your two colors in the LAB color space. (By the way, excellent work in getting this far). What will work best and be easiest to implement for you is to find the three-dimensional midpoint of an imaginary line segment joining the two points in LAB space. You can do this easily by just averaging each of the components of your two colors: the average L, average aand average b. Then convert this color back into RGB space by reversing your transformation (make sure your lighting space stays the same both ways).
使用 CIELAB 颜色,您在 LAB 颜色空间中的两种颜色中的每一种都有三个坐标。(顺便说一句,在这方面做得很好)。最适合您并且最容易实现的方法是找到连接 LAB 空间中两点的假想线段的三维中点。您只需对两种颜色的每个分量求平均值即可轻松完成此操作:平均值L、平均值a和平均值b。然后通过反转转换将此颜色转换回 RGB 空间(确保您的照明空间在两种方式下都保持相同)。
Your new color may be outside the RGB color space. You may decide to clip to the nearest visible color in this case. (Blues are especially vulnerable to this).
您的新颜色可能在 RGB 颜色空间之外。在这种情况下,您可以决定剪裁到最近的可见颜色。(蓝调特别容易受到这种影响)。
回答by Quuxplusone
Now that you have your two colors in LAB (or L*a*b*) format, you can average them together.
现在您拥有 LAB(或 L*a*b*)格式的两种颜色,您可以将它们平均在一起。
L(result) = L(first color) + L(second color) / 2
A(result) = A(first color) + A(second color) / 2
B(result) = B(first color) + B(second color) / 2
You already knew this, right? because this is what you were doing with your original RGB colors to average them.
你已经知道了,对吧?因为这是您使用原始 RGB 颜色对它们进行平均的操作。
回答by Stu
Here's a good article I wrote on color mixing in the CIE-LCh color-space, which produces a mixture that preserves hue, saturation, and luminance in a way that consistent with your eye's perception.
这是我写的一篇关于 CIE-LCh 颜色空间中的颜色混合的好文章,它产生的混合物以与眼睛感知一致的方式保留色调、饱和度和亮度。
回答by Jordan
What about converting RGB to CMYK using thisand then:
使用这个将 RGB 转换为 CMYK然后:
// CMYK colors
colorA = [2, 90, 94, 0];
colorB = [4, 0, 80, 0];
colorMixC = (colorA[0] + colorB[0]) / 2;
colorMixM = (colorA[1] + colorB[1]) / 2;
colorMixY = (colorA[2] + colorB[2]) / 2;
colorMixK = (colorA[3] + colorB[3]) / 2;
And finaly convert CMYK to RGB using this
最后使用这个将 CMYK 转换为 RGB
回答by Pylyp
You need to use CMYor RGBcolor model.
您需要使用CMY或RGB颜色模型。
Why Blue+ Yellowcannot be Gray?
为什么Blue+Yellow不能是Gray?
Blue+ Yellow= (Cyan+ Magenta) + Yellow=> Gray. Why not?
Blue+ Yellow= ( Cyan+ Magenta) + Yellow=> Gray。为什么不?
So you can use RGB (CMY) to mix colors.
因此您可以使用 RGB (CMY) 来混合颜色。
回答by Howard
Create the element you want to paint:
创建要绘制的元素:
<DIV ID="SWATCH" STYLE="HEIGHT:50PX;WIDTH:50PX;"></DIV>
Place the rgb colours you want to combine into an array (as many as you like):
将要组合的 rgb 颜色放入一个数组中(任意多):
var colourArray=['#012345','#6789AB','#CDEFED','#CBA987','#654321'];
Next convert any letters to numbers and trap them in sequence:
接下来将任何字母转换为数字并按顺序捕获它们:
var tempString=[],convertedColourArray=[];
for(i=0;i<colourArray.length;i++){
for(x=1;x<=6;x++){
var oldPigment=colourArray[i].charAt(x);
if(oldPigment<=9)tempString.push(oldPigment);
if(oldPigment=='A')tempString.push(10);
if(oldPigment=='B')tempString.push(11);
if(oldPigment=='C')tempString.push(12);
if(oldPigment=='D')tempString.push(13);
if(oldPigment=='E')tempString.push(14);
if(oldPigment=='F')tempString.push(15);}
convertedColourArray.push(tempString);
tempString=[];}
Then add each of the index position numbers together:
然后将每个索引位置号相加:
var colourTotal=0,newColour='#';
for(i=0;i<=5;i++){
for(x=0;x<convertedColourArray.length;x++)colourTotal+=parseFloat(convertedColourArray[x][i]);
Finally take the new number, convert it into the matching character and add it to the newColour variable:
最后取新数字,将其转换为匹配字符并将其添加到 newColour 变量中:
var newPigment=(Math.floor(colourTotal/colourArray.length));
if(newPigment<=9)newColour+=newPigment;
if(newPigment==10)newColour+='A';
if(newPigment==11)newColour+='B';
if(newPigment==12)newColour+='C';
if(newPigment==13)newColour+='D';
if(newPigment==14)newColour+='E';
if(newPigment==15)newColour+='F';
colourTotal=0;}
Now you can paint whatever you want with the new colour:
现在您可以使用新颜色绘制任何您想要的颜色:
document.getElementById('SWATCH').style.backgroundColor=newColour;
I hope this helps and feel free to throw eggs at it :)
我希望这会有所帮助,并随时向它扔鸡蛋:)
回答by Nils
const getHexChannel = (hex, index) => {
if (hex.length <= 5) {
const channel = hex.substr(1 + index, 1);
return `${channel}${channel}`;
}
return hex.substr(1 + index * 2, 2);
};
function hexToRGB(hex) {
if (typeof hex === 'string' && hex[0] === '#') {
return [0, 1, 2].map(i => parseInt(getHexChannel(hex, i), 16));
}
return hex;
}
function channelMixer(channelA, channelB, ammount) {
const a = channelA * (1 - ammount);
const b = channelB * ammount;
return parseInt(a + b, 10);
}
export function blendColors(colorA, colorB, ammount = 0.5) {
const rgbA = hexToRGB(colorA);
const rgbB = hexToRGB(colorB);
return [0, 1, 2].map(i => channelMixer(rgbA[i], rgbB[i], ammount));
}
export const lighten = (color, ammount) => blendColors(color, '#fff', ammount);
export const darken = (color, ammount) => blendColors(color, '#000', ammount);

