David Kendal’s Weblog

A Damn Fine Web Publication

A Liberal PHP Function for Processing HTML5 Colour Inputs Into an RGBA Quadruplet

HTML5 provides a new input type for selecting colour values, which, as yet, is unimplemented by any browser. The specification says that colours must be provided in the standard HTML hex-triplet format of a hash followed by six hexadecimal characters. Due to the obvious usability problem associated with asking people to input a cryptic sequence of characters representing a colour, not many people have yet started to use the type="color" attribute, unlike input-types such as search which can apply to all search fields on a site, and make hardly any difference at all.

However, a little back-end chicanery allows us to implement a user-friendly version of the color selector right away, which both allows users to type in the names of colours such as ‘light eggplant,’ ‘tea,’ and ‘booger,’ while also accepting hex-triplet (as required by the spec) and RGB(A) triplet/quadruplet format (for smart-arsed users).

Using a table of colours called rgb.txt (I recommend this one by Randall Munroe, as the colours were chosen by mass consensus rather than arbitrarily) which converts names to hex-triplets, and a smart piece of regular expression magic to liberally match triplets and quadruplets, I came out with this code, which returns an array(int red, int green, int blue, int alpha)—you can convert it back to a hex triplet easily enough with the built-in dechex function.

Here’s the code:

Update: I’ve altered this script slightly since this post was made—here’s the latest version.

function colormatch($color) {
  $rgbtxt = explode("\n", file_get_contents('rgb.txt'));
  $colornames = array();
  foreach ($rgbtxt as $pair) {
    $pair = explode("\t", $pair);
    $colornames[$pair[0]] = $pair[1];
  }

  if (isset($colornames[strtolower($color)])) {
    $color = $colornames[strtolower($color)]; // the hex triplet will be converted to RGB dec values later.
  }

  if (preg_match("/^(rgb(a)?)?\(?([0-9]{1,3}), ?([0-9]{1,3}), ?([0-9]{1,3})(, ?[0-9]{1,3})?\)?$/i", $color, $matches)) {
    $red = ($matches[3] > 255 ? 255 : $matches[3]);
    $green = ($matches[4] > 255 ? 255 : $matches[4]);
    $blue = ($matches[5] > 255 ? 255 : $matches[5]);
    $alpha = ($matches[7] ? ($matches[7] > 255 ? 255 : $matches[7]) : 0 ); // alpha is optional

    return array($red, $green, $blue, $alpha);

  } elseif (preg_match("/^#?(([0-9a-f])([0-9a-f])([0-9a-f]))(([0-9a-f])([0-9a-f])([0-9a-f]))?$/i", $color, $matches)) { // colors from rgb.txt are converted to (r, g, b) here.
    if ($matches[5]) { // not the short form
      $red = $matches[2].$matches[3];
      $green = $matches[4].$matches[6];
      $blue =  $matches[7].$matches[8];
    } else { // short form triplet
      $red = $matches[2].$matches[2];
      $green = $matches[3].$matches[3];
      $blue =  $matches[4].$matches[4];
    }

    return array(hexdec($red), hexdec($green), hexdec($blue), 0); // 0 for alpha--not set by hex triplet
  } else {
    return 0; // 0 == error, unmatchable. try and avoid this.
  }
}

This code, as far as I can tell, will match every single one of the following values correctly (with the rgb.txt I linked to above):

red
green
indigo
dark red
Red
Green
Indigo
Dark Red
78, 92, 156
78, 92, 156, 0
(67, 154, 243)
(67, 154, 243, 127)
rgb(67, 154, 243)
rgba(67, 154, 243, 127)
78,92,156
78,92,156,0
(67,154,243)
(67,154,243,127)
rgb(67,154,243)
rgba(67,154,243,127)
#f8ed56
#23f
f8ed56
23f
#F8ED56
#23F
F8ED56
23F

I’ve made a small demo and a test script that takes a file with each line populated by a possible colour match.

Sadly, WebKit’s color input-type doesn’t seem to be able to handle spaces in an input right now, which is likely intentional given the spec’s requirement for a hex triplet. I’d advise sticking with text if you’re going to use this script to allow users to specify colours.