寻找颜色的平均值?- 十六进制字符串

5

说明

编写一个函数,该函数将2个颜色作为参数,并返回平均颜色。

  • 参数将是两个6位十六进制字符串。这不需要进行验证。
  • 返回值应为一个6位十六进制字符串。
  • 十六进制字符串表示RGB颜色,类似于CSS中的表示方式。
  • 平均颜色是通过对每个组件(红色、绿色和蓝色)取算术平均值来确定的。

代码

 const avgColor = (str1, str2) => {
    return (str1 + str2) / 2
 }

问题

16进制数看起来像这样 0000ff 对吗?

我不确定当需要对每个组件求平均值并列出3种颜色时它的含义。如何对字符串求平均值?


一个十六进制值不是一个字符串,它是一个十六进制数值 - esqew
@Pointy 抱歉,我不理解。您的意思是“您将每一对数字解释为一个数字”吗? - mph85
2
(1) 使用子字符串获取每一对数字。 (2) 使用 parseInt(v, 16) 将每一对十六进制数转换为数字。 (3) 取平均值。 (4) 使用 .toString(16) 将每个 R、G 和 B 数字转回十六进制。 - user47589
参数将是两个6位十六进制字符串。这意味着不是2个字符串,而是2个数字吗? - mph85
这听起来像是作业。 - ian.pvd
显示剩余2条评论
5个回答

2
您可以使用以下代码片段来实现:

最初的回答:

function avg(a,b){
  const regex=/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ //regular expression to parse string
  a=regex.exec(a).slice(1)  //create array from string 'a' using regex
  b=regex.exec(b).slice(1)  //create array from string 'b' using regex
  let output=''
  for(let i=0;i<3;i++){
    const value=Math.floor(
       (
         parseInt(a[i],16) + //parse decimal from hexadecimal
         parseInt(b[i],16)   //parse decimal from hexadecimal
       )/2                   //perform averaging
     ).toString(16)          //convert back to hexadecimal
     output += (value.length<2?'0':'') + value //add leading zero if needed
  }
  return output
}

当我尝试使用2个值时,出现以下错误:"TypeError: Cannot read property 'slice' of null - mph85
很奇怪:我刚刚尝试了你的值,它运行良好! - FZs
你的修改让它工作了,但现在它是这个样子 "#7f07f"# 是一个十六进制值吗? - mph85
通常十六进制颜色以#开头标记,但如果您不需要它,可以从这里删除:let output="#" - FZs
但是这些值不是6位数吗?如果我们去掉它,那么就变成5位数了? - mph85
显示剩余4条评论

2

这是一个纯JavaScript函数:

在计算平均值之前,您必须将十六进制字符串分成三个颜色组件:

Original Answer翻译成"最初的回答":

function calcAvg(hex1,hex2) {

  //parsed into decimal from hex
  //for each color pair
let hexC11 = parseInt(hex1.slice(0,2), 16);  
let hexC12 = parseInt(hex1.slice(2,4), 16);
let hexC13 = parseInt(hex1.slice(4,6), 16);
let hexC21 = parseInt(hex2.slice(0,2), 16);
let hexC22 = parseInt(hex2.slice(2,4), 16);
let hexC23 = parseInt(hex2.slice(4,6), 16);

  //calculate mean for each color pair
let colorMean1 = (hexC11 + hexC21) / 2;
let colorMean2 = (hexC12 + hexC22) / 2;
let colorMean3 = (hexC13 + hexC23) / 2;

  //convert back to hex
let colorMean1Hex = colorMean1.toString(16);
let colorMean2Hex = colorMean2.toString(16);
let colorMean3Hex = colorMean3.toString(16);

  //pad hex if needed
if (colorMean1Hex.length == 1)
  colorMean1Hex = "0" + colorMean1Hex;
if (colorMean2Hex.length == 1)
  colorMean2Hex = "0" + colorMean2Hex;
if (colorMean3Hex.length == 1)
  colorMean3Hex = "0" + colorMean3Hex;

  //merge color pairs back into one hex color
let avgColor = colorMean1Hex +
    colorMean2Hex +
    colorMean3Hex;

  return avgColor;
}

let avg = calcAvg("999999","777777");
console.log(avg);

当我使用一个示例运行时,会返回一个答案,如下所示:"7f.8007f.8"。 - mph85

1
十六进制就像这样的 0000ff 对吗?是的。更详细地说,"十六进制字符串" 的每两个字符表示一个十六进制颜色(每个数字有16个数字),而不是十进制(每个数字有10个数字)。因此,前两个字符表示颜色的红色值,接下来的两个字符表示颜色的绿色值,最后两个字符表示颜色的蓝色值。将这些值组合起来就得到了最终的颜色。进一步说明,"ff" 十六进制值等于十进制值256。十六进制数字从0-9开始,然后继续到a、b、c、d、e和f,然后再回到0,因此十六进制的 "0f" 数字在十进制中等于16。十六进制的 "10" 数字在十进制中等于17。从0到17在十六进制中计数如下:"00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0f","10"。

脑袋有点混乱,我得重新启动一下,看看是否完全理解了这个。 - mph85
1
@mph85 所以,如果你拿你的例子“0000ff”来说。在十进制值中,它意味着红色值为0,绿色值为0,蓝色值为256。这种表示颜色的方式被称为RGB(红,绿,蓝)。使用RGB值的每个组件的0-256值,你可以创建任何颜色(基本上)。使用十六进制数代替十进制数,意味着你可以使用6个字符来表示任何RGB颜色,而不需要使用9个字符来表示任何RGB颜色(如你使用十进制数时所需)。 - dqhendricks
还是我需要将其转换为数字,然后再求平均值? - mph85
1
@mph85 是的,但老师可能希望你将其转换回十六进制字符串作为最终答案。纯JavaScript有一种将十六进制转换为十进制以及反之的方法:https://dev59.com/HnVD5IYBdhLWcg3wL4mM - dqhendricks
1
@mph85 所以很可能要将字符串分成三个部分,将每个部分转换为十进制,求出十进制值的平均数,然后再将平均数转换回十六进制部分,最后组合成最终字符串。也许有一种方法可以使用十六进制数创建平均数,但我不确定。如果可以的话,您就可以跳过转换为十进制和回转换的步骤。 - dqhendricks
显示剩余2条评论

1
为了计算十六进制字符串值的平均值,你需要:
  • 将十六进制字符串转换为整数(类似于parseInt('0000ff', 16)
  • 拆分颜色组件
  • 计算每个颜色组件的平均值
  • 从颜色组件重构最终值
  • 将结果转换回带填充的十六进制字符串,你可以参考这个问题如何在JavaScript中将十进制转换为十六进制

完整代码示例类似于

const avgColor = (str1, str2) => {
    // Convert the hexadecimal string to integer
    const color1 = parseInt(str1, 16);
    const color2 = parseInt(str2, 16);

    let avgColor = 0;
    for (let i = 0; i < 3; i++) {
        // Split the color components
        comp1 = (color1 >> (8 * i)) & 0xff;
        comp2 = (color2 >> (8 * i)) & 0xff;
        // Calculate the average value for each color component
        let v = parseInt((comp1 + comp2) / 2) << 8 * i;

        // Reconstruct the final value from the color components
        avgColor += parseInt((comp1 + comp2) / 2) << 8 * i;
    }

    return decimalToHex(avgColor, 6);
}

// Reference from https://dev59.com/HnVD5IYBdhLWcg3wL4mM
function decimalToHex(d, padding) {
    var hex = Number(d).toString(16);
    padding = typeof (padding) === "undefined" || padding === null ? padding = 2 : padding;

    while (hex.length < padding) {
        hex = "0" + hex;
    }

    return hex;
}

console.log(avgColor("0000ff", "ff0000"))


这个方法并不适用于它,因为他们需要在计算平均值之前将十六进制字符串分割成其三个颜色组件。 “平均颜色是通过对每个组件取算术平均值来确定的。” - HBlackorby
@HBlackorby 感谢您指出这个问题!我已经在我的答案中修复了它。 - Xiangyu.Wu

-1
如果您可以使用jQuery,这个问题有一个jQuery插件 -
$.xcolor.average(color, color)

嗨,谢谢你。我相信硬件只是想要一个用原生JS编写的函数,但我会点赞因为你向我展示了另一种方法。 - mph85

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接