1

I'm building Color picker. If user picks a color square, it converts to approximate color name.

For example, if user picks colors for C0C0C0 or BEBEBE, both color string will be converted to grey even though each color have a specific color name.

I can't even figure out how I can approach this problem and Google didn't help me either! :(

Here is my sudo code for the color function

getApproxColor = (colorString) => {
    if(`BBBBBB` <= colorString  <= 'CCCCCC') {
        return 'grey'
    }
    ...
}

Should I write whole color name on this function? Is there any formula for hex color?

merry-go-round
  • 4,533
  • 10
  • 54
  • 102
  • 1
    That is a tricky question. The best way I can think of to handle this is to use http://www.thecolorapi.com/. – smsalisbury Oct 25 '17 at 15:32
  • Thanks for answering! But unfortunatelly I cant call ajax request just for color . But the wbsite looks super usedul in the future. I apprrciate it – merry-go-round Oct 25 '17 at 15:49

2 Answers2

1

TL;DR: Just use this library. It is a mixed of what I said but with the complexity mentioned by Kaiido resolved: http://chir.ag/projects/ntc/


Keeping the original answer here but it won't work completely. See above.

Well, every color is a combination of 6 digits in hexa.

If you convert that number into an int, let's say, BEBEBE is 12500670.

You could then have a small table with every key/pair of known name and their corresponding integer value.

Then is just a matter of finding the closest integer number in your table.

Edit:

Basically, if you have your color picker and it says that the person chose 'BEBEBE' you would have to:

  1. Convert the hexa to decimal. There are multiple tutorials and online tools, I won't go into detail here. It is not very hard.
  2. You would then have a table, object, array, whatever you want sorted by decimal value and their correspondent name. Example: http://cloford.com/resources/colours/500col.htm You could use this table that has the hexa codes and convert them into decimal. [{ name: 'grey', hexa: 'bebebe', decimal: '12500670' }, [...] //Insert more colors ]
  3. You could then iterate over your list comparing the decimal input by the user against the one you have and stop when you reach a number highers than yours, and you can store the one you just found and the previous one.
  4. You find the difference between the one you just found and the previous one, and the one with the less difference is the closest one
  5. Profit
sebastianf182
  • 9,844
  • 3
  • 34
  • 66
  • Thanks for answering! Could you provide very simple example? For example,,, if(color < 'BEBEBE') { return 'grey' } <- Does this work? – merry-go-round Oct 26 '17 at 01:11
  • Al please vote up my question too! I don't know why someone didn't like me question – merry-go-round Oct 26 '17 at 01:12
  • 1
    Well, people is downvoting probably because your question does not have any research of things you tried, but I agree people should explain why they are downvoting. About the example, I'll try to explain a little more but you should try to research a little bit, because I cannot detail it that much. – sebastianf182 Oct 26 '17 at 01:18
  • 1
    It is fine, some people they just downvote anyway. So, your pseudocode does not look so bad. But I am not sure <> can be used on hexa. If it works, you dont need to convert them. – sebastianf182 Oct 26 '17 at 01:31
  • I may miss something in this answer, but using the hex color as is is a no go for me. You can't relly on this to sort colors. https://jsfiddle.net/dgz25w01 – Kaiido Oct 26 '17 at 01:56
  • @Kaiido Interesting. Since the hexa are representations for the Red, Green and Blue, it might be needed to actually have 3 different values and not one big int. Like redInt, greenInt and blueInt. That should be more precise. – sebastianf182 Oct 26 '17 at 02:00
  • @sfratini that would be the same. What OP asks is really not that easy. A better first step would be to [convert these hex values to hsl](https://stackoverflow.com/questions/3732046/how-do-you-get-the-hue-of-a-xxxxxx-colour), then from the hue rotation we can get on which color it is based, but we would also need to look at saturation and luminance to get greys and whites. – Kaiido Oct 26 '17 at 02:06
  • mmmm *strokes chin* – sebastianf182 Oct 26 '17 at 02:11
  • @Kaiido You were right. I just edited the answer with a library that solves the issue. It is the same basic logic I mentioned but it includes the HSL like you said. – sebastianf182 Oct 26 '17 at 02:23
1

I am not sure if it is the best way, but if I ever had to do something like this, I think I would first convert these hex values to hsl.

Then you would have to check for saturation and luminance in order to find grays and add more granularity in your findings.

Here is a rough proof of concept using only 6 base colors and with a stolen code from an older question to do this hex => hsl conversion.

inp.oninput = e => {
  if (!inp.checkValidity()) return;
  var val = inp.value;
  if (val.length !== 3 && val.length !== 6) return;
  var color = hexToName(inp.value);
  if (color) {
    inp.style.backgroundColor = '#' + val;
    log.textContent = color;
  }
}


function hexToName(hex) {
  // first get hsl correspondance
  var hsl = hexToHsl(hex);
  if(!hsl){
    return;
  }
  // get the base color
  var color = getColorName(hsl[0] * 360);
  // check saturation and luminosity
  // needs more granularity, left as an exercise for the reader
  if (hsl[1] < .5) {
    return hsl[2] <= .5 ? hsl[2] === 0? 'black' : 'darkgray' : hsl[2] === 1 ? 'white': 'gray';
  }
  return hsl[2] <= .5 ? color : 'light' + color;
}
function getColorName(hue) {
  // here you will need more work:
  // we use fixed distance for this simple demo
  var names = ['red', 'yellow', 'green', 'cyan', 'blue', 'magenta'];
  var angles = [0, 60, 120, 180, 240, 300];
  var match = angles.filter(a =>
    a - 60 <= hue && a + 60 > hue
  )[0] || 0;
  return names[angles.indexOf(match)];
}
// shamelessly stolen from https://stackoverflow.com/a/3732187/3702797
function hexToHsl(hex) {
  if (hex.length === 3) {
    hex = hex.split('').map(c => c.repeat(2)).join('');
  }
  if (hex.length !== 6) {
    return;
  }
  var r = parseInt(hex[0] + hex[1], 16);
  var g = parseInt(hex[2] + hex[3], 16);
  var b = parseInt(hex[4] + hex[5], 16);

  r /= 255, g /= 255, b /= 255;
  var max = Math.max(r, g, b),
    min = Math.min(r, g, b);
  var h, s, l = (max + min) / 2;

  if (max == min) {
    h = s = 0; // achromatic
  } else {
    var d = max - min;
    s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
    switch (max) {
      case r:
        h = (g - b) / d + (g < b ? 6 : 0);
        break;
      case g:
        h = (b - r) / d + 2;
        break;
      case b:
        h = (r - g) / d + 4;
        break;
    }
    h /= 6;
  }

  return [h, s, l];
}
#<input id="inp" type="text" pattern="[0-9a-fA-F]+">
<pre id="log"><pre>
Kaiido
  • 123,334
  • 13
  • 219
  • 285