Color Analyzer

by Marc Malignan

HTML

<input id="input" type="file">
<div id="container">
  <img id="img" src="https://dl.dropboxusercontent.com/u/80418372/album-cover.jpg"/>
  <img id="loader" src="http://mvgen.com/loader.gif">
</div>
<canvas id="cvs"></canvas>
<div id="colors"></div>

CSS

@import url(http://fonts.googleapis.com/css?family=Roboto);

body {
  margin: 0;
  background: #111;
  text-align: center;
}

#cvs {
  display: none;
}

#input {
  margin-top: 40px;
  color: #eee;
}

#container {
  position: relative;
}

#img {
  display: block;
  height: 300px;
  margin: 20px auto;
  box-shadow: 0 4px 10px rgba(0,0,0,.3);
}

#loader {
  position: absolute;
  height: 50px;
  top: 50%; left: 50%;
  margin: -25px 0 0 -25px;
}

#colors {
  line-height: 0;
  text-align: center;
}
.color {
  position: relative;
  display: inline-block;
  width: 80px;
  height: 80px;
  border-radius: 50%;
  margin: 5px;
  box-shadow: 0 4px 10px rgba(0,0,0,.3);
}
.color span {
  opacity: 0;
  position: absolute;
  top: 100%; left: 50%;
  width: 80px;
  line-height: 30px;
  margin: -10px 0 0 -40px;
  background: #eee;
  border-radius: 2px;
  font-family: 'Roboto', sans-serif;
  font-size: 14px;
  box-shadow: 0 2px 8px rgba(0,0,0,.3);
  z-index: 2;
  transition: all .2s;
}
.color:hover span {
  opacity: 1;
}

JavaScript

var colors = [];

var diff = 100; // find similar colors (high is more permissive)
var requiredMatches = 3; // match only on highest R, G, or B

// init
var img = new Image();
img.onload = analyze;
img.crossOrigin = 'anonymous';
img.src = document.getElementById('img').src;

var input = document.getElementById('input');
input.onchange = loadImg;

var loader = document.getElementById('loader');

function loadImg() {
  // clean results
  loader.style.display = 'block';
  document.getElementById('colors').innerHTML = '';

  // load event
  var reader = new FileReader();
  reader.onloadend = function(e) {
    document.getElementById('img').src = reader.result;
    img.src = reader.result;
  };
  
  // read file
  var file = this.files[0];
  if(file && (file.type==='image/jpeg' || file.type==='image/png')) {
  	reader.readAsDataURL(file);
  }
};

function rgbToHex(r, g, b) {
  return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}

function bestColor() {
  var best = colors[0];
  var toRemove = [];

  // sort color RGB by highest value    
  var cOrder = [
    { c:'r', val:best.r },
    { c:'g', val:best.g },
    { c:'b', val:best.b }
  ];
  cOrder.sort(function(a,b) {
    if(a.val > b.val) return -1;
    if(a.val < b.val) return 1;
    return 0;
  });

  for(var i=0; i<colors.length; i++) {

    var c = colors[i];
    var match = {
      r: false,
      g: false,
      b: false
    }

    // check RGB matches
    if(c.r>best.r-diff && c.r<best.r+diff) match.r = true;
    if(c.g>best.g-diff && c.g<best.g+diff) match.g = true;
    if(c.b>best.b-diff && c.b<best.b+diff) match.b = true;

    // check if similar color
    var matches = 0;
    for(var n=0; n<requiredMatches; n++) {
      if(match[cOrder[n].c]) matches++;
    }
    if(matches>(requiredMatches-1)) toRemove.push(c);
  }

  for(var i=0; i<toRemove.length; i++) {
    colors.splice(colors.indexOf(toRemove[i]), 1);
  }
  return best;
}

function analyze() {

  var cvs =...