【问题标题】:Finding average of colors? - hexadecimal strings寻找颜色的平均值? - 十六进制字符串
【发布时间】:2019-07-16 20:40:49
【问题描述】:

说明

编写一个以 2 种颜色为参数并返回平均颜色的函数。

  • 参数将是两个 6 位十六进制字符串。这不需要验证。
  • 返回值应为 6 位十六进制字符串。
  • 十六进制字符串表示 RGB 中的颜色,与 CSS 中非常相似。
  • 平均颜色是通过取每个分量的算术平均值来确定的:红色、绿色和蓝色。

代码

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

问题

十六进制类似于0000ff 对吧?

当我需要为每个组件取算术平均值并列出 3 种颜色时,我不确定这意味着什么。你如何取字符串的平均值?

【问题讨论】:

  • 您不会采用“平均字符串”。你解释每一对数字都有一个数字,然后做一个简单的数字平均。
  • 十六进制值不是字符串,而是base-16 numeric value
  • @Pointy 对不起,我不明白。 You interpret each pair of digits has a number?
  • (1) 使用子串获取每对数字。 (2) 使用parseInt(v, 16) 将每对十六进制数字转换为一个数字。 (3) 平均你的数字。 (4) 使用.toString(16)将每个R、G和B数字转换回十六进制
  • The parameters will be two 6-digit hexadecimal strings。所以这意味着不是 2 个字符串,而是 2 个数字?

标签: javascript average arrow-functions


【解决方案1】:

这是一个简单的 JS 函数:

在转换它们以计算平均值之前,您必须将十六进制字符串拆分为三个颜色分量:

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"
【解决方案2】:

你可以用这个 sn-p 做到这一点:

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
  • 你尝试了哪些值?
  • ("0000ff", "ff0000")
  • 带小号fs?
  • 是的,只是使用了下面的结尾示例
【解决方案3】:

十六进制是这样的 0000ff 对吧?

是的。

详细地说,“十六进制字符串”的每两个字符代表十六进制的颜色(每个数字 16 个数字),而不是十进制(每个数字 10 个数字)。所以前两个字符代表颜色的Red值,后两个字符代表颜色的Green值,最后两个字符代表颜色的Blue值。组合这些值会产生最终的颜色。

更详细地说,“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 就像,如果你以“0000ff”为例。在十进制值中,它表示红色值为 0,绿色值为 0,蓝色值为 256。这种表示颜色的方式称为 RGB(红、绿、蓝)。 RGB 值的每个分量都有 0-256 个值,您可以(基本上)创建任何颜色。使用十六进制数字而不是十进制数字,意味着您可以使用 6 个字符来表示任何 RGB 颜色,而不是需要 9 个字符来表示任何 RGB 颜色(就像使用小数一样)。
  • 明白了,那么取每个组件的算术平均值是什么意思?蓝色只是128吗?
  • @mph85 是的,但是老师可能希望您将其转回十六进制字符串以作为最终答案。 vanilla javascript有一种将十六进制转换为十进制的方法,反之亦然:stackoverflow.com/questions/57803/…
  • @mph85 很可能,将字符串分成三部分,将每个部分转换为十进制,平均十进制值,然后转换回十六进制部分,然后组合成最终字符串。可能有一种方法可以使用十六进制数字创建平均值,但我不确定。如果是这样,您将能够跳过转换为十进制并返回。
【解决方案4】:

为了计算一个十六进制字符串值的平均值,你需要:

  • 将十六进制字符串转换为整数(类似于parseInt('0000ff', 16)
  • 分割颜色分量
  • 计算每个颜色分量的平均值
  • 根据颜色分量重构最终值
  • 将结果转回十六进制字符串(带填充),可以参考这个问题How to convert decimal to hexadecimal in JavaScript

完整代码 sn-p 的示例类似于

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://stackoverflow.com/questions/57803/how-to-convert-decimal-to-hexadecimal-in-javascript
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 感谢您指出!我已经在我的回答中修复了它。
【解决方案5】:

如果你可以使用 jQuery,这里有一个 jQuery 插件 -

$.xcolor.average(color, color)

【讨论】:

  • 嗨,谢谢。我相信硬件只是想要一个用 vanilla JS 编写的函数,但我赞成以不同的方式向我展示。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-25
  • 1970-01-01
  • 1970-01-01
  • 2011-09-16
  • 2020-05-31
  • 2017-02-13
相关资源
最近更新 更多